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