]> git.saurik.com Git - wxWidgets.git/blame - src/unix/utilsunx.cpp
added wxFileName::MakeRelativeTo() and the tests/docs for it
[wxWidgets.git] / src / unix / utilsunx.cpp
CommitLineData
518b5d2f
VZ
1/////////////////////////////////////////////////////////////////////////////
2// Name: utilsunx.cpp
3// Purpose: generic Unix implementation of many wx functions
4// Author: Vadim Zeitlin
5// Id: $Id$
6// Copyright: (c) 1998 Robert Roebling, Vadim Zeitlin
7// Licence: wxWindows licence
8/////////////////////////////////////////////////////////////////////////////
9
10// ============================================================================
11// declarations
12// ============================================================================
13
14// ----------------------------------------------------------------------------
15// headers
16// ----------------------------------------------------------------------------
17
18#include "wx/defs.h"
19#include "wx/string.h"
20
21#include "wx/intl.h"
22#include "wx/log.h"
a37a5a73 23#include "wx/app.h"
518b5d2f
VZ
24
25#include "wx/utils.h"
26#include "wx/process.h"
bdc72a22 27#include "wx/thread.h"
518b5d2f 28
8b33ae2d
GL
29#include "wx/stream.h"
30
eadd7bd2 31#ifdef HAVE_STATFS
8f17876f 32# ifdef __BSD__
8c03f242
GD
33# include <sys/param.h>
34# include <sys/mount.h>
35# else
36# include <sys/vfs.h>
37# endif
eadd7bd2
VZ
38#endif // HAVE_STATFS
39
9952adac
VZ
40#ifdef HAVE_STATVFS
41 #include <sys/statvfs.h>
42
43 #define statfs statvfs
44#endif // HAVE_STATVFS
45
6dc6fda6
VZ
46#if wxUSE_GUI
47 #include "wx/unix/execute.h"
48#endif
518b5d2f 49
f6bcfd97
BP
50// SGI signal.h defines signal handler arguments differently depending on
51// whether _LANGUAGE_C_PLUS_PLUS is set or not - do set it
52#if defined(__SGI__) && !defined(_LANGUAGE_C_PLUS_PLUS)
53 #define _LANGUAGE_C_PLUS_PLUS 1
54#endif // SGI hack
55
518b5d2f
VZ
56#include <stdarg.h>
57#include <dirent.h>
58#include <string.h>
59#include <sys/stat.h>
60#include <sys/types.h>
61#include <unistd.h>
62#include <sys/wait.h>
63#include <pwd.h>
64#include <errno.h>
65#include <netdb.h>
66#include <signal.h>
67#include <fcntl.h> // for O_WRONLY and friends
68#include <time.h> // nanosleep() and/or usleep()
fad866f4 69#include <ctype.h> // isspace()
b12915c1 70#include <sys/time.h> // needed for FD_SETSIZE
7bcb11d3 71
0fcdf6dc 72#ifdef HAVE_UNAME
518b5d2f
VZ
73 #include <sys/utsname.h> // for uname()
74#endif // HAVE_UNAME
75
76// ----------------------------------------------------------------------------
77// conditional compilation
78// ----------------------------------------------------------------------------
79
80// many versions of Unices have this function, but it is not defined in system
81// headers - please add your system here if it is the case for your OS.
82// SunOS < 5.6 (i.e. Solaris < 2.6) and DG-UX are like this.
1363811b
VZ
83#if !defined(HAVE_USLEEP) && \
84 (defined(__SUN__) && !defined(__SunOs_5_6) && \
518b5d2f 85 !defined(__SunOs_5_7) && !defined(__SUNPRO_CC)) || \
fd9811b1 86 defined(__osf__) || defined(__EMX__)
518b5d2f
VZ
87 extern "C"
88 {
1363811b
VZ
89 #ifdef __SUN__
90 int usleep(unsigned int usec);
91 #else // !Sun
bdc72a22
VZ
92 #ifdef __EMX__
93 /* I copied this from the XFree86 diffs. AV. */
94 #define INCL_DOSPROCESS
95 #include <os2.h>
96 inline void usleep(unsigned long delay)
97 {
98 DosSleep(delay ? (delay/1000l) : 1l);
99 }
100 #else // !Sun && !EMX
101 void usleep(unsigned long usec);
102 #endif
e6daf794 103 #endif // Sun/EMX/Something else
518b5d2f 104 };
bdc72a22
VZ
105
106 #define HAVE_USLEEP 1
518b5d2f
VZ
107#endif // Unices without usleep()
108
518b5d2f
VZ
109// ============================================================================
110// implementation
111// ============================================================================
112
113// ----------------------------------------------------------------------------
114// sleeping
115// ----------------------------------------------------------------------------
116
117void wxSleep(int nSecs)
118{
119 sleep(nSecs);
120}
121
122void wxUsleep(unsigned long milliseconds)
123{
b12915c1 124#if defined(HAVE_NANOSLEEP)
518b5d2f 125 timespec tmReq;
13111b2a 126 tmReq.tv_sec = (time_t)(milliseconds / 1000);
518b5d2f
VZ
127 tmReq.tv_nsec = (milliseconds % 1000) * 1000 * 1000;
128
129 // we're not interested in remaining time nor in return value
130 (void)nanosleep(&tmReq, (timespec *)NULL);
b12915c1 131#elif defined(HAVE_USLEEP)
518b5d2f
VZ
132 // uncomment this if you feel brave or if you are sure that your version
133 // of Solaris has a safe usleep() function but please notice that usleep()
134 // is known to lead to crashes in MT programs in Solaris 2.[67] and is not
135 // documented as MT-Safe
ea18eed9 136 #if defined(__SUN__) && wxUSE_THREADS
518b5d2f
VZ
137 #error "usleep() cannot be used in MT programs under Solaris."
138 #endif // Sun
139
140 usleep(milliseconds * 1000); // usleep(3) wants microseconds
b12915c1
VZ
141#elif defined(HAVE_SLEEP)
142 // under BeOS sleep() takes seconds (what about other platforms, if any?)
143 sleep(milliseconds * 1000);
518b5d2f
VZ
144#else // !sleep function
145 #error "usleep() or nanosleep() function required for wxUsleep"
146#endif // sleep function
147}
148
149// ----------------------------------------------------------------------------
150// process management
151// ----------------------------------------------------------------------------
152
50567b69 153int wxKill(long pid, wxSignal sig, wxKillError *rc)
518b5d2f 154{
50567b69
VZ
155 int err = kill((pid_t)pid, (int)sig);
156 if ( rc )
157 {
158 switch ( err )
159 {
160 case 0:
161 *rc = wxKILL_OK;
162 break;
163
164 case EINVAL:
165 *rc = wxKILL_BAD_SIGNAL;
166 break;
167
168 case EPERM:
169 *rc = wxKILL_ACCESS_DENIED;
170 break;
171
172 case ESRCH:
173 *rc = wxKILL_NO_PROCESS;
174 break;
175
176 default:
177 // this goes against Unix98 docs so log it
178 wxLogDebug(_T("unexpected kill(2) return value %d"), err);
179
180 // something else...
181 *rc = wxKILL_ERROR;
182 }
183 }
184
185 return err;
518b5d2f
VZ
186}
187
fad866f4
KB
188#define WXEXECUTE_NARGS 127
189
518b5d2f
VZ
190long wxExecute( const wxString& command, bool sync, wxProcess *process )
191{
223d09f6 192 wxCHECK_MSG( !command.IsEmpty(), 0, wxT("can't exec empty command") );
518b5d2f
VZ
193
194 int argc = 0;
05079acc 195 wxChar *argv[WXEXECUTE_NARGS];
fad866f4 196 wxString argument;
05079acc 197 const wxChar *cptr = command.c_str();
223d09f6 198 wxChar quotechar = wxT('\0'); // is arg quoted?
fad866f4 199 bool escaped = FALSE;
518b5d2f 200
0ed9a934 201 // split the command line in arguments
fad866f4
KB
202 do
203 {
223d09f6
KB
204 argument=wxT("");
205 quotechar = wxT('\0');
0ed9a934 206
fad866f4 207 // eat leading whitespace:
05079acc 208 while ( wxIsspace(*cptr) )
fad866f4 209 cptr++;
0ed9a934 210
223d09f6 211 if ( *cptr == wxT('\'') || *cptr == wxT('"') )
fad866f4 212 quotechar = *cptr++;
0ed9a934 213
fad866f4
KB
214 do
215 {
223d09f6 216 if ( *cptr == wxT('\\') && ! escaped )
fad866f4
KB
217 {
218 escaped = TRUE;
219 cptr++;
220 continue;
221 }
0ed9a934 222
fad866f4 223 // all other characters:
0ed9a934 224 argument += *cptr++;
fad866f4 225 escaped = FALSE;
0ed9a934
VZ
226
227 // have we reached the end of the argument?
228 if ( (*cptr == quotechar && ! escaped)
223d09f6
KB
229 || (quotechar == wxT('\0') && wxIsspace(*cptr))
230 || *cptr == wxT('\0') )
fad866f4 231 {
0ed9a934 232 wxASSERT_MSG( argc < WXEXECUTE_NARGS,
223d09f6 233 wxT("too many arguments in wxExecute") );
0ed9a934 234
05079acc
OK
235 argv[argc] = new wxChar[argument.length() + 1];
236 wxStrcpy(argv[argc], argument.c_str());
fad866f4 237 argc++;
0ed9a934 238
fad866f4 239 // if not at end of buffer, swallow last character:
0ed9a934
VZ
240 if(*cptr)
241 cptr++;
242
fad866f4
KB
243 break; // done with this one, start over
244 }
0ed9a934
VZ
245 } while(*cptr);
246 } while(*cptr);
fad866f4 247 argv[argc] = NULL;
0ed9a934
VZ
248
249 // do execute the command
518b5d2f
VZ
250 long lRc = wxExecute(argv, sync, process);
251
0ed9a934 252 // clean up
fad866f4 253 argc = 0;
0ed9a934 254 while( argv[argc] )
fad866f4 255 delete [] argv[argc++];
518b5d2f
VZ
256
257 return lRc;
258}
259
2c8e4738
VZ
260// ----------------------------------------------------------------------------
261// wxShell
262// ----------------------------------------------------------------------------
263
264static wxString wxMakeShellCommand(const wxString& command)
518b5d2f
VZ
265{
266 wxString cmd;
cd6ce4a9 267 if ( !command )
2c8e4738
VZ
268 {
269 // just an interactive shell
cd6ce4a9 270 cmd = _T("xterm");
2c8e4738 271 }
518b5d2f 272 else
2c8e4738
VZ
273 {
274 // execute command in a shell
275 cmd << _T("/bin/sh -c '") << command << _T('\'');
276 }
277
278 return cmd;
279}
280
281bool wxShell(const wxString& command)
282{
283 return wxExecute(wxMakeShellCommand(command), TRUE /* sync */) == 0;
284}
285
286bool wxShell(const wxString& command, wxArrayString& output)
287{
288 wxCHECK_MSG( !!command, FALSE, _T("can't exec shell non interactively") );
518b5d2f 289
2c8e4738 290 return wxExecute(wxMakeShellCommand(command), output);
518b5d2f
VZ
291}
292
6dc6fda6
VZ
293#if wxUSE_GUI
294
518b5d2f
VZ
295void wxHandleProcessTermination(wxEndProcessData *proc_data)
296{
018e2f13
VZ
297 // notify user about termination if required
298 if ( proc_data->process )
c556f198 299 {
447f908a 300 proc_data->process->OnTerminate(proc_data->pid, proc_data->exitcode);
c556f198 301 }
447f908a 302
018e2f13
VZ
303 // clean up
304 if ( proc_data->pid > 0 )
c556f198 305 {
018e2f13 306 delete proc_data;
0ed9a934 307 }
018e2f13 308 else
0ed9a934 309 {
447f908a 310 // let wxExecute() know that the process has terminated
018e2f13 311 proc_data->pid = 0;
518b5d2f
VZ
312 }
313}
314
6dc6fda6
VZ
315#endif // wxUSE_GUI
316
cd6ce4a9
VZ
317// ----------------------------------------------------------------------------
318// wxStream classes to support IO redirection in wxExecute
319// ----------------------------------------------------------------------------
6dc6fda6 320
1e6feb95
VZ
321#if wxUSE_STREAMS
322
cd6ce4a9
VZ
323class wxProcessFileInputStream : public wxInputStream
324{
325public:
326 wxProcessFileInputStream(int fd) { m_fd = fd; }
327 ~wxProcessFileInputStream() { close(m_fd); }
8b33ae2d 328
cd6ce4a9 329 virtual bool Eof() const;
8b33ae2d 330
cd6ce4a9 331protected:
8b33ae2d
GL
332 size_t OnSysRead(void *buffer, size_t bufsize);
333
cd6ce4a9 334protected:
8b33ae2d
GL
335 int m_fd;
336};
337
cd6ce4a9
VZ
338class wxProcessFileOutputStream : public wxOutputStream
339{
340public:
341 wxProcessFileOutputStream(int fd) { m_fd = fd; }
342 ~wxProcessFileOutputStream() { close(m_fd); }
8b33ae2d 343
cd6ce4a9 344protected:
8b33ae2d
GL
345 size_t OnSysWrite(const void *buffer, size_t bufsize);
346
cd6ce4a9 347protected:
8b33ae2d
GL
348 int m_fd;
349};
350
cd6ce4a9 351bool wxProcessFileInputStream::Eof() const
8b33ae2d 352{
cd6ce4a9
VZ
353 if ( m_lasterror == wxSTREAM_EOF )
354 return TRUE;
355
356 // check if there is any input available
357 struct timeval tv;
358 tv.tv_sec = 0;
359 tv.tv_usec = 0;
360
361 fd_set readfds;
362 FD_ZERO(&readfds);
363 FD_SET(m_fd, &readfds);
364 switch ( select(m_fd + 1, &readfds, NULL, NULL, &tv) )
365 {
366 case -1:
367 wxLogSysError(_("Impossible to get child process input"));
368 // fall through
8b33ae2d 369
cd6ce4a9
VZ
370 case 0:
371 return TRUE;
8b33ae2d 372
cd6ce4a9
VZ
373 default:
374 wxFAIL_MSG(_T("unexpected select() return value"));
375 // still fall through
376
377 case 1:
378 // input available: check if there is any
379 return wxInputStream::Eof();
8b33ae2d 380 }
8b33ae2d
GL
381}
382
cd6ce4a9 383size_t wxProcessFileInputStream::OnSysRead(void *buffer, size_t bufsize)
8b33ae2d 384{
cd6ce4a9
VZ
385 int ret = read(m_fd, buffer, bufsize);
386 if ( ret == 0 )
387 {
388 m_lasterror = wxSTREAM_EOF;
389 }
390 else if ( ret == -1 )
391 {
392 m_lasterror = wxSTREAM_READ_ERROR;
393 ret = 0;
394 }
395 else
396 {
397 m_lasterror = wxSTREAM_NOERROR;
398 }
8b33ae2d 399
cd6ce4a9 400 return ret;
8b33ae2d
GL
401}
402
403size_t wxProcessFileOutputStream::OnSysWrite(const void *buffer, size_t bufsize)
404{
cd6ce4a9
VZ
405 int ret = write(m_fd, buffer, bufsize);
406 if ( ret == -1 )
407 {
408 m_lasterror = wxSTREAM_WRITE_ERROR;
409 ret = 0;
8b33ae2d 410 }
cd6ce4a9
VZ
411 else
412 {
413 m_lasterror = wxSTREAM_NOERROR;
414 }
415
8b33ae2d
GL
416 return ret;
417}
418
0e300ddd
VZ
419// ----------------------------------------------------------------------------
420// wxStreamTempBuffer
421// ----------------------------------------------------------------------------
422
423/*
424 Extract of a mail to wx-users to give the context of the problem we are
425 trying to solve here:
426
427 MC> If I run the command:
428 MC> find . -name "*.h" -exec grep linux {} \;
429 MC> in the exec sample synchronously from the 'Capture command output'
430 MC> menu, wxExecute never returns. I have to xkill it. Has anyone
431 MC> else encountered this?
432
433 Yes, I can reproduce it too.
434
435 I even think I understand why it happens: before launching the external
436 command we set up a pipe with a valid file descriptor on the reading side
437 when the output is redirected. So the subprocess happily writes to it ...
438 until the pipe buffer (which is usually quite big on Unix, I think the
439 default is 4Mb) is full. Then the writing process stops and waits until we
440 read some data from the pipe to be able to continue writing to it but we
441 never do it because we wait until it terminates to start reading and so we
442 have a classical deadlock.
443
444 Here is the fix: we now read the output as soon as it appears into a temp
445 buffer (wxStreamTempBuffer object) and later just stuff it back into the
446 stream when the process terminates. See supporting code in wxExecute()
447 itself as well.
448*/
449
450class wxStreamTempBuffer
451{
452public:
453 wxStreamTempBuffer();
454
455 // call to associate a stream with this buffer, otherwise nothing happens
456 // at all
457 void Init(wxInputStream *stream);
458
459 // check for input on our stream and cache it in our buffer if any
460 void Update();
461
462 ~wxStreamTempBuffer();
463
464private:
465 // the stream we're buffering, if NULL we don't do anything at all
466 wxInputStream *m_stream;
467
468 // the buffer of size m_size (NULL if m_size == 0)
469 void *m_buffer;
470
471 // the size of the buffer
472 size_t m_size;
473};
474
475wxStreamTempBuffer::wxStreamTempBuffer()
476{
477 m_stream = NULL;
478 m_buffer = NULL;
479 m_size = 0;
480}
481
482void wxStreamTempBuffer::Init(wxInputStream *stream)
483{
484 m_stream = stream;
485}
486
487void wxStreamTempBuffer::Update()
488{
489 if ( m_stream && !m_stream->Eof() )
490 {
491 // realloc in blocks of 1Kb - surely not the best strategy but which
492 // one is?
493 static const size_t incSize = 1024;
494
495 void *buf = realloc(m_buffer, m_size + incSize);
496 if ( !buf )
497 {
498 // don't read any more, we don't have enough memory to do it
499 m_stream = NULL;
500 }
501 else // got memory for the buffer
502 {
503 m_buffer = buf;
504 m_stream->Read((char *)m_buffer + m_size, incSize);
505 m_size += incSize;
506 }
507 }
508}
509
510wxStreamTempBuffer::~wxStreamTempBuffer()
511{
512 if ( m_buffer )
513 {
514 m_stream->Ungetch(m_buffer, m_size);
515 free(m_buffer);
516 }
517}
518
1e6feb95
VZ
519#endif // wxUSE_STREAMS
520
6dc6fda6
VZ
521long wxExecute(wxChar **argv,
522 bool sync,
cd6ce4a9 523 wxProcess *process)
518b5d2f 524{
f6bcfd97 525 // for the sync execution, we return -1 to indicate failure, but for async
accb3257
VZ
526 // case we return 0 which is never a valid PID
527 //
528 // we define this as a macro, not a variable, to avoid compiler warnings
529 // about "ERROR_RETURN_CODE value may be clobbered by fork()"
530 #define ERROR_RETURN_CODE ((sync) ? -1 : 0)
f6bcfd97 531
accb3257 532 wxCHECK_MSG( *argv, ERROR_RETURN_CODE, wxT("can't exec empty command") );
518b5d2f 533
05079acc
OK
534#if wxUSE_UNICODE
535 int mb_argc = 0;
536 char *mb_argv[WXEXECUTE_NARGS];
537
e90c1d2a
VZ
538 while (argv[mb_argc])
539 {
cd6ce4a9
VZ
540 wxWX2MBbuf mb_arg = wxConvertWX2MB(argv[mb_argc]);
541 mb_argv[mb_argc] = strdup(mb_arg);
542 mb_argc++;
05079acc
OK
543 }
544 mb_argv[mb_argc] = (char *) NULL;
e90c1d2a
VZ
545
546 // this macro will free memory we used above
547 #define ARGS_CLEANUP \
345b0247 548 for ( mb_argc = 0; mb_argv[mb_argc]; mb_argc++ ) \
e90c1d2a
VZ
549 free(mb_argv[mb_argc])
550#else // ANSI
551 // no need for cleanup
552 #define ARGS_CLEANUP
553
05079acc 554 wxChar **mb_argv = argv;
e90c1d2a 555#endif // Unicode/ANSI
518b5d2f 556
e90c1d2a 557#if wxUSE_GUI
518b5d2f 558 // create pipes
e90c1d2a 559 int end_proc_detect[2];
cd6ce4a9 560 if ( pipe(end_proc_detect) == -1 )
518b5d2f
VZ
561 {
562 wxLogSysError( _("Pipe creation failed") );
cd6ce4a9 563 wxLogError( _("Failed to execute '%s'\n"), *argv );
e90c1d2a
VZ
564
565 ARGS_CLEANUP;
566
accb3257 567 return ERROR_RETURN_CODE;
518b5d2f 568 }
e90c1d2a 569#endif // wxUSE_GUI
518b5d2f 570
f6bcfd97
BP
571 // pipes for inter process communication
572 int pipeIn[2], // stdin
573 pipeOut[2], // stdout
574 pipeErr[2]; // stderr
575
cd6ce4a9 576 pipeIn[0] = pipeIn[1] =
f6bcfd97
BP
577 pipeOut[0] = pipeOut[1] =
578 pipeErr[0] = pipeErr[1] = -1;
cd6ce4a9
VZ
579
580 if ( process && process->IsRedirected() )
8b33ae2d 581 {
f6bcfd97 582 if ( pipe(pipeIn) == -1 || pipe(pipeOut) == -1 || pipe(pipeErr) == -1 )
8b33ae2d 583 {
cd6ce4a9
VZ
584#if wxUSE_GUI
585 // free previously allocated resources
8b33ae2d
GL
586 close(end_proc_detect[0]);
587 close(end_proc_detect[1]);
cd6ce4a9
VZ
588#endif // wxUSE_GUI
589
590 wxLogSysError( _("Pipe creation failed") );
591 wxLogError( _("Failed to execute '%s'\n"), *argv );
8b33ae2d
GL
592
593 ARGS_CLEANUP;
594
accb3257 595 return ERROR_RETURN_CODE;
8b33ae2d
GL
596 }
597 }
8b33ae2d 598
518b5d2f 599 // fork the process
0fcdf6dc 600#ifdef HAVE_VFORK
518b5d2f
VZ
601 pid_t pid = vfork();
602#else
603 pid_t pid = fork();
604#endif
cd6ce4a9
VZ
605
606 if ( pid == -1 ) // error?
518b5d2f 607 {
8b33ae2d
GL
608#if wxUSE_GUI
609 close(end_proc_detect[0]);
610 close(end_proc_detect[1]);
cd6ce4a9
VZ
611 close(pipeIn[0]);
612 close(pipeIn[1]);
613 close(pipeOut[0]);
614 close(pipeOut[1]);
f6bcfd97
BP
615 close(pipeErr[0]);
616 close(pipeErr[1]);
cd6ce4a9
VZ
617#endif // wxUSE_GUI
618
518b5d2f 619 wxLogSysError( _("Fork failed") );
e90c1d2a
VZ
620
621 ARGS_CLEANUP;
622
accb3257 623 return ERROR_RETURN_CODE;
518b5d2f 624 }
cd6ce4a9 625 else if ( pid == 0 ) // we're in child
518b5d2f 626 {
e90c1d2a 627#if wxUSE_GUI
518b5d2f 628 close(end_proc_detect[0]); // close reading side
e90c1d2a 629#endif // wxUSE_GUI
518b5d2f 630
cd6ce4a9 631 // These lines close the open file descriptors to to avoid any
518b5d2f 632 // input/output which might block the process or irritate the user. If
cd6ce4a9
VZ
633 // one wants proper IO for the subprocess, the right thing to do is to
634 // start an xterm executing it.
635 if ( !sync )
518b5d2f 636 {
518b5d2f
VZ
637 for ( int fd = 0; fd < FD_SETSIZE; fd++ )
638 {
f6bcfd97 639 if ( fd == pipeIn[0] || fd == pipeOut[1] || fd == pipeErr[1]
e90c1d2a 640#if wxUSE_GUI
cd6ce4a9 641 || fd == end_proc_detect[1]
e90c1d2a 642#endif // wxUSE_GUI
cd6ce4a9
VZ
643 )
644 {
645 // don't close this one, we still need it
646 continue;
647 }
e90c1d2a 648
cd6ce4a9 649 // leave stderr opened too, it won't do any hurm
e90c1d2a 650 if ( fd != STDERR_FILENO )
518b5d2f
VZ
651 close(fd);
652 }
653 }
654
f6bcfd97 655 // redirect stdio, stdout and stderr
cd6ce4a9
VZ
656 if ( pipeIn[0] != -1 )
657 {
658 if ( dup2(pipeIn[0], STDIN_FILENO) == -1 ||
f6bcfd97
BP
659 dup2(pipeOut[1], STDOUT_FILENO) == -1 ||
660 dup2(pipeErr[1], STDERR_FILENO) == -1 )
cd6ce4a9 661 {
f6bcfd97 662 wxLogSysError(_("Failed to redirect child process input/output"));
cd6ce4a9 663 }
518b5d2f 664
cd6ce4a9
VZ
665 close(pipeIn[0]);
666 close(pipeOut[1]);
f6bcfd97 667 close(pipeErr[1]);
cd6ce4a9 668 }
518b5d2f 669
05079acc 670 execvp (*mb_argv, mb_argv);
518b5d2f
VZ
671
672 // there is no return after successful exec()
518b5d2f 673 _exit(-1);
1d8dd65e
VZ
674
675 // some compilers complain about missing return - of course, they
676 // should know that exit() doesn't return but what else can we do if
677 // they don't?
678#if defined(__VMS) || defined(__INTEL_COMPILER)
679 return 0;
680#endif
518b5d2f 681 }
cd6ce4a9 682 else // we're in parent
518b5d2f 683 {
cd6ce4a9
VZ
684 ARGS_CLEANUP;
685
686 // pipe initialization: construction of the wxStreams
0e300ddd
VZ
687#if wxUSE_STREAMS
688 wxStreamTempBuffer bufIn, bufErr;
689#endif // wxUSE_STREAMS
690
cd6ce4a9
VZ
691 if ( process && process->IsRedirected() )
692 {
1e6feb95 693#if wxUSE_STREAMS
0e300ddd 694 // in/out for subprocess correspond to our out/in
cd6ce4a9
VZ
695 wxOutputStream *outStream = new wxProcessFileOutputStream(pipeIn[1]);
696 wxInputStream *inStream = new wxProcessFileInputStream(pipeOut[0]);
f6bcfd97
BP
697 wxInputStream *errStream = new wxProcessFileInputStream(pipeErr[0]);
698
1e6feb95 699 process->SetPipeStreams(inStream, outStream, errStream);
0e300ddd
VZ
700
701 bufIn.Init(inStream);
702 bufErr.Init(inStream);
1e6feb95
VZ
703#endif // wxUSE_STREAMS
704
cd6ce4a9
VZ
705 close(pipeIn[0]); // close reading side
706 close(pipeOut[1]); // close writing side
f6bcfd97 707 close(pipeErr[1]); // close writing side
cd6ce4a9
VZ
708 }
709
fac3b423 710#if wxUSE_GUI && !defined(__WXMICROWIN__)
518b5d2f 711 wxEndProcessData *data = new wxEndProcessData;
ab857a4e 712
518b5d2f
VZ
713 if ( sync )
714 {
cd6ce4a9
VZ
715 // we may have process for capturing the program output, but it's
716 // not used in wxEndProcessData in the case of sync execution
518b5d2f
VZ
717 data->process = NULL;
718
719 // sync execution: indicate it by negating the pid
cd6ce4a9
VZ
720 data->pid = -pid;
721 data->tag = wxAddProcessCallback(data, end_proc_detect[0]);
722
ab857a4e 723 close(end_proc_detect[1]); // close writing side
518b5d2f 724
cd6ce4a9
VZ
725 wxBusyCursor bc;
726 wxWindowDisabler wd;
727
0e300ddd
VZ
728 // data->pid will be set to 0 from GTK_EndProcessDetector when the
729 // process terminates
730 while ( data->pid != 0 )
731 {
732#if wxUSE_STREAMS
733 bufIn.Update();
734 bufErr.Update();
735#endif // wxUSE_STREAMS
736
737 // give GTK+ a chance to call GTK_EndProcessDetector here and
738 // also repaint the GUI
518b5d2f 739 wxYield();
0e300ddd 740 }
518b5d2f
VZ
741
742 int exitcode = data->exitcode;
743
744 delete data;
745
746 return exitcode;
747 }
cd6ce4a9 748 else // async execution
518b5d2f
VZ
749 {
750 // async execution, nothing special to do - caller will be
ab857a4e 751 // notified about the process termination if process != NULL, data
518b5d2f 752 // will be deleted in GTK_EndProcessDetector
8b33ae2d
GL
753 data->process = process;
754 data->pid = pid;
755 data->tag = wxAddProcessCallback(data, end_proc_detect[0]);
cd6ce4a9 756
ab857a4e 757 close(end_proc_detect[1]); // close writing side
518b5d2f
VZ
758
759 return pid;
760 }
e90c1d2a 761#else // !wxUSE_GUI
223d09f6 762 wxASSERT_MSG( sync, wxT("async execution not supported yet") );
e90c1d2a
VZ
763
764 int exitcode = 0;
765 if ( waitpid(pid, &exitcode, 0) == -1 || !WIFEXITED(exitcode) )
766 {
767 wxLogSysError(_("Waiting for subprocess termination failed"));
768 }
769
770 return exitcode;
771#endif // wxUSE_GUI
518b5d2f
VZ
772 }
773}
774
accb3257 775#undef ERROR_RETURN_CODE
f6bcfd97
BP
776#undef ARGS_CLEANUP
777
518b5d2f
VZ
778// ----------------------------------------------------------------------------
779// file and directory functions
780// ----------------------------------------------------------------------------
781
05079acc 782const wxChar* wxGetHomeDir( wxString *home )
518b5d2f
VZ
783{
784 *home = wxGetUserHome( wxString() );
181cbcf4 785 wxString tmp;
518b5d2f 786 if ( home->IsEmpty() )
223d09f6 787 *home = wxT("/");
181cbcf4
JJ
788#ifdef __VMS
789 tmp = *home;
790 if ( tmp.Last() != wxT(']'))
791 if ( tmp.Last() != wxT('/')) *home << wxT('/');
792#endif
518b5d2f
VZ
793 return home->c_str();
794}
795
05079acc
OK
796#if wxUSE_UNICODE
797const wxMB2WXbuf wxGetUserHome( const wxString &user )
e90c1d2a 798#else // just for binary compatibility -- there is no 'const' here
518b5d2f 799char *wxGetUserHome( const wxString &user )
05079acc 800#endif
518b5d2f
VZ
801{
802 struct passwd *who = (struct passwd *) NULL;
803
0fb67cd1 804 if ( !user )
518b5d2f 805 {
e90c1d2a 806 wxChar *ptr;
518b5d2f 807
223d09f6 808 if ((ptr = wxGetenv(wxT("HOME"))) != NULL)
518b5d2f
VZ
809 {
810 return ptr;
811 }
223d09f6 812 if ((ptr = wxGetenv(wxT("USER"))) != NULL || (ptr = wxGetenv(wxT("LOGNAME"))) != NULL)
518b5d2f 813 {
e90c1d2a 814 who = getpwnam(wxConvertWX2MB(ptr));
518b5d2f
VZ
815 }
816
817 // We now make sure the the user exists!
818 if (who == NULL)
819 {
820 who = getpwuid(getuid());
821 }
822 }
823 else
824 {
05079acc 825 who = getpwnam (user.mb_str());
518b5d2f
VZ
826 }
827
af111fc3 828 return wxConvertMB2WX(who ? who->pw_dir : 0);
518b5d2f
VZ
829}
830
831// ----------------------------------------------------------------------------
0fb67cd1 832// network and user id routines
518b5d2f
VZ
833// ----------------------------------------------------------------------------
834
0fb67cd1
VZ
835// retrieve either the hostname or FQDN depending on platform (caller must
836// check whether it's one or the other, this is why this function is for
837// private use only)
05079acc 838static bool wxGetHostNameInternal(wxChar *buf, int sz)
518b5d2f 839{
223d09f6 840 wxCHECK_MSG( buf, FALSE, wxT("NULL pointer in wxGetHostNameInternal") );
518b5d2f 841
223d09f6 842 *buf = wxT('\0');
518b5d2f
VZ
843
844 // we're using uname() which is POSIX instead of less standard sysinfo()
845#if defined(HAVE_UNAME)
cc743a6f 846 struct utsname uts;
518b5d2f
VZ
847 bool ok = uname(&uts) != -1;
848 if ( ok )
849 {
e90c1d2a 850 wxStrncpy(buf, wxConvertMB2WX(uts.nodename), sz - 1);
223d09f6 851 buf[sz] = wxT('\0');
518b5d2f
VZ
852 }
853#elif defined(HAVE_GETHOSTNAME)
854 bool ok = gethostname(buf, sz) != -1;
0fb67cd1 855#else // no uname, no gethostname
223d09f6 856 wxFAIL_MSG(wxT("don't know host name for this machine"));
518b5d2f
VZ
857
858 bool ok = FALSE;
0fb67cd1 859#endif // uname/gethostname
518b5d2f
VZ
860
861 if ( !ok )
862 {
863 wxLogSysError(_("Cannot get the hostname"));
864 }
865
866 return ok;
867}
868
05079acc 869bool wxGetHostName(wxChar *buf, int sz)
0fb67cd1
VZ
870{
871 bool ok = wxGetHostNameInternal(buf, sz);
872
873 if ( ok )
874 {
875 // BSD systems return the FQDN, we only want the hostname, so extract
876 // it (we consider that dots are domain separators)
223d09f6 877 wxChar *dot = wxStrchr(buf, wxT('.'));
0fb67cd1
VZ
878 if ( dot )
879 {
880 // nuke it
223d09f6 881 *dot = wxT('\0');
0fb67cd1
VZ
882 }
883 }
884
885 return ok;
886}
887
05079acc 888bool wxGetFullHostName(wxChar *buf, int sz)
0fb67cd1
VZ
889{
890 bool ok = wxGetHostNameInternal(buf, sz);
891
892 if ( ok )
893 {
223d09f6 894 if ( !wxStrchr(buf, wxT('.')) )
0fb67cd1 895 {
e90c1d2a 896 struct hostent *host = gethostbyname(wxConvertWX2MB(buf));
0fb67cd1
VZ
897 if ( !host )
898 {
899 wxLogSysError(_("Cannot get the official hostname"));
900
901 ok = FALSE;
902 }
903 else
904 {
905 // the canonical name
e90c1d2a 906 wxStrncpy(buf, wxConvertMB2WX(host->h_name), sz);
0fb67cd1
VZ
907 }
908 }
909 //else: it's already a FQDN (BSD behaves this way)
910 }
911
912 return ok;
913}
914
05079acc 915bool wxGetUserId(wxChar *buf, int sz)
518b5d2f
VZ
916{
917 struct passwd *who;
918
223d09f6 919 *buf = wxT('\0');
518b5d2f
VZ
920 if ((who = getpwuid(getuid ())) != NULL)
921 {
e90c1d2a 922 wxStrncpy (buf, wxConvertMB2WX(who->pw_name), sz - 1);
518b5d2f
VZ
923 return TRUE;
924 }
925
926 return FALSE;
927}
928
05079acc 929bool wxGetUserName(wxChar *buf, int sz)
518b5d2f
VZ
930{
931 struct passwd *who;
518b5d2f 932
223d09f6 933 *buf = wxT('\0');
b12915c1
VZ
934 if ((who = getpwuid (getuid ())) != NULL)
935 {
936 // pw_gecos field in struct passwd is not standard
bd3277fe 937#ifdef HAVE_PW_GECOS
b12915c1 938 char *comma = strchr(who->pw_gecos, ',');
518b5d2f
VZ
939 if (comma)
940 *comma = '\0'; // cut off non-name comment fields
e90c1d2a 941 wxStrncpy (buf, wxConvertMB2WX(who->pw_gecos), sz - 1);
b12915c1 942#else // !HAVE_PW_GECOS
0fcdf6dc 943 wxStrncpy (buf, wxConvertMB2WX(who->pw_name), sz - 1);
b12915c1 944#endif // HAVE_PW_GECOS/!HAVE_PW_GECOS
518b5d2f
VZ
945 return TRUE;
946 }
947
948 return FALSE;
949}
950
bdc72a22
VZ
951wxString wxGetOsDescription()
952{
953#ifndef WXWIN_OS_DESCRIPTION
954 #error WXWIN_OS_DESCRIPTION should be defined in config.h by configure
955#else
956 return WXWIN_OS_DESCRIPTION;
957#endif
958}
959
bd3277fe
VZ
960// this function returns the GUI toolkit version in GUI programs, but OS
961// version in non-GUI ones
962#if !wxUSE_GUI
963
964int wxGetOsVersion(int *majorVsn, int *minorVsn)
965{
966 int major, minor;
967 char name[256];
968
969 if ( sscanf(WXWIN_OS_DESCRIPTION, "%s %d.%d", name, &major, &minor) != 3 )
970 {
971 // unreckognized uname string format
972 major = minor = -1;
973 }
974
975 if ( majorVsn )
976 *majorVsn = major;
977 if ( minorVsn )
978 *minorVsn = minor;
979
980 return wxUNIX;
981}
982
983#endif // !wxUSE_GUI
984
985long wxGetFreeMemory()
986{
987#if defined(__LINUX__)
988 // get it from /proc/meminfo
989 FILE *fp = fopen("/proc/meminfo", "r");
990 if ( fp )
991 {
992 long memFree = -1;
993
994 char buf[1024];
995 if ( fgets(buf, WXSIZEOF(buf), fp) && fgets(buf, WXSIZEOF(buf), fp) )
996 {
997 long memTotal, memUsed;
998 sscanf(buf, "Mem: %ld %ld %ld", &memTotal, &memUsed, &memFree);
999 }
1000
1001 fclose(fp);
1002
1003 return memFree;
1004 }
1005#elif defined(__SUN__) && defined(_SC_AVPHYS_PAGES)
1006 return sysconf(_SC_AVPHYS_PAGES)*sysconf(_SC_PAGESIZE);
1007//#elif defined(__FREEBSD__) -- might use sysctl() to find it out, probably
1008#endif
1009
1010 // can't find it out
1011 return -1;
1012}
1013
eadd7bd2
VZ
1014bool wxGetDiskSpace(const wxString& path, wxLongLong *pTotal, wxLongLong *pFree)
1015{
9952adac 1016#if defined(HAVE_STATFS) || defined(HAVE_STATVFS)
eadd7bd2
VZ
1017 struct statfs fs;
1018 if ( statfs(path, &fs) != 0 )
1019 {
1020 wxLogSysError("Failed to get file system statistics");
1021
1022 return FALSE;
1023 }
1024
9952adac
VZ
1025 // under Solaris we might have to use fs.f_frsize instead as I think it
1026 // may be a multiple of the block size in general (TODO)
1027
eadd7bd2
VZ
1028 if ( pTotal )
1029 {
1030 *pTotal = wxLongLong(fs.f_blocks) * fs.f_bsize;
1031 }
1032
1033 if ( pFree )
1034 {
1035 *pFree = wxLongLong(fs.f_bavail) * fs.f_bsize;
1036 }
1037
1038 return TRUE;
1039#endif // HAVE_STATFS
1040
1041 return FALSE;
1042}
1043
8fd0d89b
VZ
1044// ----------------------------------------------------------------------------
1045// env vars
1046// ----------------------------------------------------------------------------
1047
97b305b7 1048bool wxGetEnv(const wxString& var, wxString *value)
308978f6
VZ
1049{
1050 // wxGetenv is defined as getenv()
1051 wxChar *p = wxGetenv(var);
1052 if ( !p )
1053 return FALSE;
1054
1055 if ( value )
1056 {
1057 *value = p;
1058 }
1059
1060 return TRUE;
1061}
1062
8fd0d89b
VZ
1063bool wxSetEnv(const wxString& variable, const wxChar *value)
1064{
1065#if defined(HAVE_SETENV)
d90b2df8
VZ
1066 return setenv(variable.mb_str(),
1067 value ? (const char *)wxString(value).mb_str()
1068 : NULL,
1069 1 /* overwrite */) == 0;
8fd0d89b
VZ
1070#elif defined(HAVE_PUTENV)
1071 wxString s = variable;
1072 if ( value )
1073 s << _T('=') << value;
1074
1075 // transform to ANSI
1076 const char *p = s.mb_str();
1077
1078 // the string will be free()d by libc
1079 char *buf = (char *)malloc(strlen(p) + 1);
1080 strcpy(buf, p);
1081
1082 return putenv(buf) == 0;
1083#else // no way to set an env var
1084 return FALSE;
1085#endif
1086}
1087
a37a5a73
VZ
1088// ----------------------------------------------------------------------------
1089// signal handling
1090// ----------------------------------------------------------------------------
1091
1092#if wxUSE_ON_FATAL_EXCEPTION
1093
1094#include <signal.h>
1095
f6bcfd97 1096static void wxFatalSignalHandler(wxTYPE_SA_HANDLER)
a37a5a73
VZ
1097{
1098 if ( wxTheApp )
1099 {
1100 // give the user a chance to do something special about this
1101 wxTheApp->OnFatalException();
1102 }
1103
1104 abort();
1105}
1106
1107bool wxHandleFatalExceptions(bool doit)
1108{
1109 // old sig handlers
1110 static bool s_savedHandlers = FALSE;
1111 static struct sigaction s_handlerFPE,
1112 s_handlerILL,
1113 s_handlerBUS,
1114 s_handlerSEGV;
1115
1116 bool ok = TRUE;
1117 if ( doit && !s_savedHandlers )
1118 {
1119 // install the signal handler
1120 struct sigaction act;
1121
1122 // some systems extend it with non std fields, so zero everything
1123 memset(&act, 0, sizeof(act));
1124
1125 act.sa_handler = wxFatalSignalHandler;
1126 sigemptyset(&act.sa_mask);
1127 act.sa_flags = 0;
1128
1129 ok &= sigaction(SIGFPE, &act, &s_handlerFPE) == 0;
1130 ok &= sigaction(SIGILL, &act, &s_handlerILL) == 0;
1131 ok &= sigaction(SIGBUS, &act, &s_handlerBUS) == 0;
1132 ok &= sigaction(SIGSEGV, &act, &s_handlerSEGV) == 0;
1133 if ( !ok )
1134 {
1135 wxLogDebug(_T("Failed to install our signal handler."));
1136 }
1137
1138 s_savedHandlers = TRUE;
1139 }
1140 else if ( s_savedHandlers )
1141 {
1142 // uninstall the signal handler
1143 ok &= sigaction(SIGFPE, &s_handlerFPE, NULL) == 0;
1144 ok &= sigaction(SIGILL, &s_handlerILL, NULL) == 0;
1145 ok &= sigaction(SIGBUS, &s_handlerBUS, NULL) == 0;
1146 ok &= sigaction(SIGSEGV, &s_handlerSEGV, NULL) == 0;
1147 if ( !ok )
1148 {
1149 wxLogDebug(_T("Failed to uninstall our signal handler."));
1150 }
1151
1152 s_savedHandlers = FALSE;
1153 }
1154 //else: nothing to do
1155
1156 return ok;
1157}
1158
1159#endif // wxUSE_ON_FATAL_EXCEPTION
1160
518b5d2f
VZ
1161// ----------------------------------------------------------------------------
1162// error and debug output routines (deprecated, use wxLog)
1163// ----------------------------------------------------------------------------
1164
1165void wxDebugMsg( const char *format, ... )
1166{
1167 va_list ap;
1168 va_start( ap, format );
1169 vfprintf( stderr, format, ap );
1170 fflush( stderr );
1171 va_end(ap);
1172}
1173
1174void wxError( const wxString &msg, const wxString &title )
1175{
05079acc 1176 wxFprintf( stderr, _("Error ") );
223d09f6
KB
1177 if (!title.IsNull()) wxFprintf( stderr, wxT("%s "), WXSTRINGCAST(title) );
1178 if (!msg.IsNull()) wxFprintf( stderr, wxT(": %s"), WXSTRINGCAST(msg) );
1179 wxFprintf( stderr, wxT(".\n") );
518b5d2f
VZ
1180}
1181
1182void wxFatalError( const wxString &msg, const wxString &title )
1183{
05079acc 1184 wxFprintf( stderr, _("Error ") );
223d09f6
KB
1185 if (!title.IsNull()) wxFprintf( stderr, wxT("%s "), WXSTRINGCAST(title) );
1186 if (!msg.IsNull()) wxFprintf( stderr, wxT(": %s"), WXSTRINGCAST(msg) );
1187 wxFprintf( stderr, wxT(".\n") );
518b5d2f
VZ
1188 exit(3); // the same exit code as for abort()
1189}
93ccaed8 1190