]> git.saurik.com Git - wxWidgets.git/blob - src/unix/utilsunx.cpp
Added DoSetSize and DoMoveWindow to generic wxStaticLine.
[wxWidgets.git] / src / unix / utilsunx.cpp
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"
23 #include "wx/app.h"
24
25 #include "wx/utils.h"
26 #include "wx/process.h"
27 #include "wx/thread.h"
28
29 #include "wx/wfstream.h"
30
31 #ifdef HAVE_STATFS
32 # ifdef __BSD__
33 # include <sys/param.h>
34 # include <sys/mount.h>
35 # else
36 # include <sys/vfs.h>
37 # endif
38 #endif // HAVE_STATFS
39
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
43 #ifdef HAVE_STATVFS
44 #include <sys/statvfs.h>
45
46 #define statfs statvfs
47 #define wxStatFs statvfs_t
48 #elif HAVE_STATFS
49 #define wxStatFs struct statfs
50 #endif // HAVE_STAT[V]FS
51
52 #if wxUSE_GUI
53 #include "wx/unix/execute.h"
54 #endif
55
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
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()
75 #include <ctype.h> // isspace()
76 #include <sys/time.h> // needed for FD_SETSIZE
77
78 #ifdef HAVE_UNAME
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.
89 #if !defined(HAVE_USLEEP) && \
90 (defined(__SUN__) && !defined(__SunOs_5_6) && \
91 !defined(__SunOs_5_7) && !defined(__SUNPRO_CC)) || \
92 defined(__osf__) || defined(__EMX__)
93 extern "C"
94 {
95 #ifdef __SUN__
96 int usleep(unsigned int usec);
97 #else // !Sun
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
109 #endif // Sun/EMX/Something else
110 };
111
112 #define HAVE_USLEEP 1
113 #endif // Unices without usleep()
114
115 // ============================================================================
116 // implementation
117 // ============================================================================
118
119 // ----------------------------------------------------------------------------
120 // sleeping
121 // ----------------------------------------------------------------------------
122
123 void wxSleep(int nSecs)
124 {
125 sleep(nSecs);
126 }
127
128 void wxUsleep(unsigned long milliseconds)
129 {
130 #if defined(HAVE_NANOSLEEP)
131 timespec tmReq;
132 tmReq.tv_sec = (time_t)(milliseconds / 1000);
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);
137 #elif defined(HAVE_USLEEP)
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
142 #if defined(__SUN__) && wxUSE_THREADS
143 #error "usleep() cannot be used in MT programs under Solaris."
144 #endif // Sun
145
146 usleep(milliseconds * 1000); // usleep(3) wants microseconds
147 #elif defined(HAVE_SLEEP)
148 // under BeOS sleep() takes seconds (what about other platforms, if any?)
149 sleep(milliseconds * 1000);
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
159 int wxKill(long pid, wxSignal sig, wxKillError *rc)
160 {
161 int err = kill((pid_t)pid, (int)sig);
162 if ( rc )
163 {
164 switch ( errno )
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;
192 }
193
194 #define WXEXECUTE_NARGS 127
195
196 long wxExecute( const wxString& command, int flags, wxProcess *process )
197 {
198 wxCHECK_MSG( !command.IsEmpty(), 0, wxT("can't exec empty command") );
199
200 int argc = 0;
201 wxChar *argv[WXEXECUTE_NARGS];
202 wxString argument;
203 const wxChar *cptr = command.c_str();
204 wxChar quotechar = wxT('\0'); // is arg quoted?
205 bool escaped = FALSE;
206
207 // split the command line in arguments
208 do
209 {
210 argument=wxT("");
211 quotechar = wxT('\0');
212
213 // eat leading whitespace:
214 while ( wxIsspace(*cptr) )
215 cptr++;
216
217 if ( *cptr == wxT('\'') || *cptr == wxT('"') )
218 quotechar = *cptr++;
219
220 do
221 {
222 if ( *cptr == wxT('\\') && ! escaped )
223 {
224 escaped = TRUE;
225 cptr++;
226 continue;
227 }
228
229 // all other characters:
230 argument += *cptr++;
231 escaped = FALSE;
232
233 // have we reached the end of the argument?
234 if ( (*cptr == quotechar && ! escaped)
235 || (quotechar == wxT('\0') && wxIsspace(*cptr))
236 || *cptr == wxT('\0') )
237 {
238 wxASSERT_MSG( argc < WXEXECUTE_NARGS,
239 wxT("too many arguments in wxExecute") );
240
241 argv[argc] = new wxChar[argument.length() + 1];
242 wxStrcpy(argv[argc], argument.c_str());
243 argc++;
244
245 // if not at end of buffer, swallow last character:
246 if(*cptr)
247 cptr++;
248
249 break; // done with this one, start over
250 }
251 } while(*cptr);
252 } while(*cptr);
253 argv[argc] = NULL;
254
255 // do execute the command
256 long lRc = wxExecute(argv, flags, process);
257
258 // clean up
259 argc = 0;
260 while( argv[argc] )
261 delete [] argv[argc++];
262
263 return lRc;
264 }
265
266 // ----------------------------------------------------------------------------
267 // wxShell
268 // ----------------------------------------------------------------------------
269
270 static wxString wxMakeShellCommand(const wxString& command)
271 {
272 wxString cmd;
273 if ( !command )
274 {
275 // just an interactive shell
276 cmd = _T("xterm");
277 }
278 else
279 {
280 // execute command in a shell
281 cmd << _T("/bin/sh -c '") << command << _T('\'');
282 }
283
284 return cmd;
285 }
286
287 bool wxShell(const wxString& command)
288 {
289 return wxExecute(wxMakeShellCommand(command), wxEXEC_SYNC) == 0;
290 }
291
292 bool wxShell(const wxString& command, wxArrayString& output)
293 {
294 wxCHECK_MSG( !!command, FALSE, _T("can't exec shell non interactively") );
295
296 return wxExecute(wxMakeShellCommand(command), output);
297 }
298
299 // Shutdown or reboot the PC
300 bool 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
322 #if wxUSE_GUI
323
324 void wxHandleProcessTermination(wxEndProcessData *proc_data)
325 {
326 // notify user about termination if required
327 if ( proc_data->process )
328 {
329 proc_data->process->OnTerminate(proc_data->pid, proc_data->exitcode);
330 }
331
332 // clean up
333 if ( proc_data->pid > 0 )
334 {
335 delete proc_data;
336 }
337 else
338 {
339 // let wxExecute() know that the process has terminated
340 proc_data->pid = 0;
341 }
342 }
343
344 #endif // wxUSE_GUI
345
346 // ----------------------------------------------------------------------------
347 // wxStream classes to support IO redirection in wxExecute
348 // ----------------------------------------------------------------------------
349
350 #if wxUSE_STREAMS
351
352 // ----------------------------------------------------------------------------
353 // wxProcessFileInputStream: stream for reading from a pipe
354 // ----------------------------------------------------------------------------
355
356 class wxProcessFileInputStream : public wxFileInputStream
357 {
358 public:
359 wxProcessFileInputStream(int fd) : wxFileInputStream(fd) { }
360
361 // return TRUE if we have anything to read, don't block
362 bool IsAvailable() const;
363 };
364
365 bool wxProcessFileInputStream::IsAvailable() const
366 {
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
375 const int fd = m_file->fd();
376
377 fd_set readfds;
378 FD_ZERO(&readfds);
379 FD_SET(fd, &readfds);
380 switch ( select(fd + 1, &readfds, NULL, NULL, &tv) )
381 {
382 case -1:
383 wxLogSysError(_("Impossible to get child process input"));
384 // fall through
385
386 case 0:
387 return TRUE;
388
389 default:
390 wxFAIL_MSG(_T("unexpected select() return value"));
391 // still fall through
392
393 case 1:
394 // input available
395 return TRUE;
396 }
397 }
398
399 // ----------------------------------------------------------------------------
400 // wxStreamTempInputBuffer
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
419 default is 4Kb) is full. Then the writing process stops and waits until we
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
425 buffer (wxStreamTempInputBuffer object) and later just stuff it back into the
426 stream when the process terminates. See supporting code in wxExecute()
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!
432 */
433
434 class wxStreamTempInputBuffer
435 {
436 public:
437 wxStreamTempInputBuffer();
438
439 // call to associate a stream with this buffer, otherwise nothing happens
440 // at all
441 void Init(wxProcessFileInputStream *stream);
442
443 // check for input on our stream and cache it in our buffer if any
444 void Update();
445
446 ~wxStreamTempInputBuffer();
447
448 private:
449 // the stream we're buffering, if NULL we don't do anything at all
450 wxProcessFileInputStream *m_stream;
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
459 wxStreamTempInputBuffer::wxStreamTempInputBuffer()
460 {
461 m_stream = NULL;
462 m_buffer = NULL;
463 m_size = 0;
464 }
465
466 void wxStreamTempInputBuffer::Init(wxProcessFileInputStream *stream)
467 {
468 m_stream = stream;
469 }
470
471 void wxStreamTempInputBuffer::Update()
472 {
473 if ( m_stream && m_stream->IsAvailable() )
474 {
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;
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);
489 m_size += m_stream->LastRead();
490 }
491 }
492 }
493
494 wxStreamTempInputBuffer::~wxStreamTempInputBuffer()
495 {
496 if ( m_buffer )
497 {
498 m_stream->Ungetch(m_buffer, m_size);
499 free(m_buffer);
500 }
501 }
502
503 #endif // wxUSE_STREAMS
504
505 // ----------------------------------------------------------------------------
506 // wxPipe: this encapsulates pipe() system call
507 // ----------------------------------------------------------------------------
508
509 class wxPipe
510 {
511 public:
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
578 private:
579 int m_fds[2];
580 };
581
582 // ----------------------------------------------------------------------------
583 // wxExecute: the real worker function
584 // ----------------------------------------------------------------------------
585 #ifdef __VMS
586 #pragma message disable codeunreachable
587 #endif
588
589 long wxExecute(wxChar **argv,
590 int flags,
591 wxProcess *process)
592 {
593 // for the sync execution, we return -1 to indicate failure, but for async
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()"
598 #define ERROR_RETURN_CODE ((flags & wxEXEC_SYNC) ? -1 : 0)
599
600 wxCHECK_MSG( *argv, ERROR_RETURN_CODE, wxT("can't exec empty command") );
601
602 #if wxUSE_UNICODE
603 int mb_argc = 0;
604 char *mb_argv[WXEXECUTE_NARGS];
605
606 while (argv[mb_argc])
607 {
608 wxWX2MBbuf mb_arg = wxConvertWX2MB(argv[mb_argc]);
609 mb_argv[mb_argc] = strdup(mb_arg);
610 mb_argc++;
611 }
612 mb_argv[mb_argc] = (char *) NULL;
613
614 // this macro will free memory we used above
615 #define ARGS_CLEANUP \
616 for ( mb_argc = 0; mb_argv[mb_argc]; mb_argc++ ) \
617 free(mb_argv[mb_argc])
618 #else // ANSI
619 // no need for cleanup
620 #define ARGS_CLEANUP
621
622 wxChar **mb_argv = argv;
623 #endif // Unicode/ANSI
624
625 #if wxUSE_GUI
626 // create pipes
627 wxPipe pipeEndProcDetect;
628 if ( !pipeEndProcDetect.Create() )
629 {
630 wxLogError( _("Failed to execute '%s'\n"), *argv );
631
632 ARGS_CLEANUP;
633
634 return ERROR_RETURN_CODE;
635 }
636 #endif // wxUSE_GUI
637
638 // pipes for inter process communication
639 wxPipe pipeIn, // stdin
640 pipeOut, // stdout
641 pipeErr; // stderr
642
643 if ( process && process->IsRedirected() )
644 {
645 if ( !pipeIn.Create() || !pipeOut.Create() || !pipeErr.Create() )
646 {
647 wxLogError( _("Failed to execute '%s'\n"), *argv );
648
649 ARGS_CLEANUP;
650
651 return ERROR_RETURN_CODE;
652 }
653 }
654
655 // fork the process
656 #ifdef HAVE_VFORK
657 pid_t pid = vfork();
658 #else
659 pid_t pid = fork();
660 #endif
661
662 if ( pid == -1 ) // error?
663 {
664 wxLogSysError( _("Fork failed") );
665
666 ARGS_CLEANUP;
667
668 return ERROR_RETURN_CODE;
669 }
670 else if ( pid == 0 ) // we're in child
671 {
672 // These lines close the open file descriptors to to avoid any
673 // input/output which might block the process or irritate the user. If
674 // one wants proper IO for the subprocess, the right thing to do is to
675 // start an xterm executing it.
676 if ( !(flags & wxEXEC_SYNC) )
677 {
678 for ( int fd = 0; fd < FD_SETSIZE; fd++ )
679 {
680 if ( fd == pipeIn[wxPipe::Read]
681 || fd == pipeOut[wxPipe::Write]
682 || fd == pipeErr[wxPipe::Write]
683 #if wxUSE_GUI
684 || fd == pipeEndProcDetect[wxPipe::Write]
685 #endif // wxUSE_GUI
686 )
687 {
688 // don't close this one, we still need it
689 continue;
690 }
691
692 // leave stderr opened too, it won't do any harm
693 if ( fd != STDERR_FILENO )
694 close(fd);
695 }
696 }
697
698 #ifndef __VMS
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();
704 }
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
713
714 // redirect stdin, stdout and stderr
715 if ( pipeIn.IsOk() )
716 {
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 )
720 {
721 wxLogSysError(_("Failed to redirect child process input/output"));
722 }
723
724 pipeIn.Close();
725 pipeOut.Close();
726 pipeErr.Close();
727 }
728
729 execvp (*mb_argv, mb_argv);
730
731 // there is no return after successful exec()
732 _exit(-1);
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?
737 //
738 // and, sure enough, other compilers complain about unreachable code
739 // after exit() call, so we can just always have return here...
740 #if defined(__VMS) || defined(__INTEL_COMPILER)
741 return 0;
742 #endif
743 }
744 else // we're in parent
745 {
746 ARGS_CLEANUP;
747
748 // prepare for IO redirection
749
750 #if wxUSE_STREAMS
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;
755 #endif // wxUSE_STREAMS
756
757 if ( process && process->IsRedirected() )
758 {
759 #if wxUSE_STREAMS
760 wxOutputStream *inStream =
761 new wxFileOutputStream(pipeIn.Detach(wxPipe::Write));
762
763 wxProcessFileInputStream *outStream =
764 new wxProcessFileInputStream(pipeOut.Detach(wxPipe::Read));
765
766 wxProcessFileInputStream *errStream =
767 new wxProcessFileInputStream(pipeErr.Detach(wxPipe::Read));
768
769 process->SetPipeStreams(outStream, inStream, errStream);
770
771 bufOut.Init(outStream);
772 bufErr.Init(errStream);
773 #endif // wxUSE_STREAMS
774 }
775
776 if ( pipeIn.IsOk() )
777 {
778 pipeIn.Close();
779 pipeOut.Close();
780 pipeErr.Close();
781 }
782
783 #if wxUSE_GUI && !defined(__WXMICROWIN__)
784 wxEndProcessData *data = new wxEndProcessData;
785
786 data->tag = wxAddProcessCallback
787 (
788 data,
789 pipeEndProcDetect.Detach(wxPipe::Read)
790 );
791
792 pipeEndProcDetect.Close();
793
794 if ( flags & wxEXEC_SYNC )
795 {
796 // we may have process for capturing the program output, but it's
797 // not used in wxEndProcessData in the case of sync execution
798 data->process = NULL;
799
800 // sync execution: indicate it by negating the pid
801 data->pid = -pid;
802
803 wxBusyCursor bc;
804 wxWindowDisabler wd;
805
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
811 bufOut.Update();
812 bufErr.Update();
813 #endif // wxUSE_STREAMS
814
815 // give GTK+ a chance to call GTK_EndProcessDetector here and
816 // also repaint the GUI
817 wxYield();
818 }
819
820 int exitcode = data->exitcode;
821
822 delete data;
823
824 return exitcode;
825 }
826 else // async execution
827 {
828 // async execution, nothing special to do - caller will be
829 // notified about the process termination if process != NULL, data
830 // will be deleted in GTK_EndProcessDetector
831 data->process = process;
832 data->pid = pid;
833
834 return pid;
835 }
836 #else // !wxUSE_GUI
837
838 wxASSERT_MSG( flags & wxEXEC_SYNC,
839 wxT("async execution not supported yet") );
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
849 }
850
851 return ERROR_RETURN_CODE;
852 }
853 #ifdef __VMS
854 #pragma message enable codeunreachable
855 #endif
856
857 #undef ERROR_RETURN_CODE
858 #undef ARGS_CLEANUP
859
860 // ----------------------------------------------------------------------------
861 // file and directory functions
862 // ----------------------------------------------------------------------------
863
864 const wxChar* wxGetHomeDir( wxString *home )
865 {
866 *home = wxGetUserHome( wxString() );
867 wxString tmp;
868 if ( home->IsEmpty() )
869 *home = wxT("/");
870 #ifdef __VMS
871 tmp = *home;
872 if ( tmp.Last() != wxT(']'))
873 if ( tmp.Last() != wxT('/')) *home << wxT('/');
874 #endif
875 return home->c_str();
876 }
877
878 #if wxUSE_UNICODE
879 const wxMB2WXbuf wxGetUserHome( const wxString &user )
880 #else // just for binary compatibility -- there is no 'const' here
881 char *wxGetUserHome( const wxString &user )
882 #endif
883 {
884 struct passwd *who = (struct passwd *) NULL;
885
886 if ( !user )
887 {
888 wxChar *ptr;
889
890 if ((ptr = wxGetenv(wxT("HOME"))) != NULL)
891 {
892 return ptr;
893 }
894 if ((ptr = wxGetenv(wxT("USER"))) != NULL || (ptr = wxGetenv(wxT("LOGNAME"))) != NULL)
895 {
896 who = getpwnam(wxConvertWX2MB(ptr));
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 {
907 who = getpwnam (user.mb_str());
908 }
909
910 return wxConvertMB2WX(who ? who->pw_dir : 0);
911 }
912
913 // ----------------------------------------------------------------------------
914 // network and user id routines
915 // ----------------------------------------------------------------------------
916
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)
920 static bool wxGetHostNameInternal(wxChar *buf, int sz)
921 {
922 wxCHECK_MSG( buf, FALSE, wxT("NULL pointer in wxGetHostNameInternal") );
923
924 *buf = wxT('\0');
925
926 // we're using uname() which is POSIX instead of less standard sysinfo()
927 #if defined(HAVE_UNAME)
928 struct utsname uts;
929 bool ok = uname(&uts) != -1;
930 if ( ok )
931 {
932 wxStrncpy(buf, wxConvertMB2WX(uts.nodename), sz - 1);
933 buf[sz] = wxT('\0');
934 }
935 #elif defined(HAVE_GETHOSTNAME)
936 bool ok = gethostname(buf, sz) != -1;
937 #else // no uname, no gethostname
938 wxFAIL_MSG(wxT("don't know host name for this machine"));
939
940 bool ok = FALSE;
941 #endif // uname/gethostname
942
943 if ( !ok )
944 {
945 wxLogSysError(_("Cannot get the hostname"));
946 }
947
948 return ok;
949 }
950
951 bool wxGetHostName(wxChar *buf, int sz)
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)
959 wxChar *dot = wxStrchr(buf, wxT('.'));
960 if ( dot )
961 {
962 // nuke it
963 *dot = wxT('\0');
964 }
965 }
966
967 return ok;
968 }
969
970 bool wxGetFullHostName(wxChar *buf, int sz)
971 {
972 bool ok = wxGetHostNameInternal(buf, sz);
973
974 if ( ok )
975 {
976 if ( !wxStrchr(buf, wxT('.')) )
977 {
978 struct hostent *host = gethostbyname(wxConvertWX2MB(buf));
979 if ( !host )
980 {
981 wxLogSysError(_("Cannot get the official hostname"));
982
983 ok = FALSE;
984 }
985 else
986 {
987 // the canonical name
988 wxStrncpy(buf, wxConvertMB2WX(host->h_name), sz);
989 }
990 }
991 //else: it's already a FQDN (BSD behaves this way)
992 }
993
994 return ok;
995 }
996
997 bool wxGetUserId(wxChar *buf, int sz)
998 {
999 struct passwd *who;
1000
1001 *buf = wxT('\0');
1002 if ((who = getpwuid(getuid ())) != NULL)
1003 {
1004 wxStrncpy (buf, wxConvertMB2WX(who->pw_name), sz - 1);
1005 return TRUE;
1006 }
1007
1008 return FALSE;
1009 }
1010
1011 bool wxGetUserName(wxChar *buf, int sz)
1012 {
1013 struct passwd *who;
1014
1015 *buf = wxT('\0');
1016 if ((who = getpwuid (getuid ())) != NULL)
1017 {
1018 // pw_gecos field in struct passwd is not standard
1019 #ifdef HAVE_PW_GECOS
1020 char *comma = strchr(who->pw_gecos, ',');
1021 if (comma)
1022 *comma = '\0'; // cut off non-name comment fields
1023 wxStrncpy (buf, wxConvertMB2WX(who->pw_gecos), sz - 1);
1024 #else // !HAVE_PW_GECOS
1025 wxStrncpy (buf, wxConvertMB2WX(who->pw_name), sz - 1);
1026 #endif // HAVE_PW_GECOS/!HAVE_PW_GECOS
1027 return TRUE;
1028 }
1029
1030 return FALSE;
1031 }
1032
1033 #ifndef __WXMAC__
1034 wxString 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 }
1042 #endif
1043
1044 // this function returns the GUI toolkit version in GUI programs, but OS
1045 // version in non-GUI ones
1046 #if !wxUSE_GUI
1047
1048 int 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
1069 unsigned long wxGetProcessId()
1070 {
1071 return (unsigned long)getpid();
1072 }
1073
1074 long 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
1103 bool wxGetDiskSpace(const wxString& path, wxLongLong *pTotal, wxLongLong *pFree)
1104 {
1105 #if defined(HAVE_STATFS) || defined(HAVE_STATVFS)
1106 // the case to "char *" is needed for AIX 4.3
1107 wxStatFs fs;
1108 if ( statfs((char *)path.fn_str(), &fs) != 0 )
1109 {
1110 wxLogSysError("Failed to get file system statistics");
1111
1112 return FALSE;
1113 }
1114
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
1122
1123 if ( pTotal )
1124 {
1125 *pTotal = wxLongLong(fs.f_blocks) * blockSize;
1126 }
1127
1128 if ( pFree )
1129 {
1130 *pFree = wxLongLong(fs.f_bavail) * blockSize;
1131 }
1132
1133 return TRUE;
1134 #else // !HAVE_STATFS && !HAVE_STATVFS
1135 return FALSE;
1136 #endif // HAVE_STATFS
1137 }
1138
1139 // ----------------------------------------------------------------------------
1140 // env vars
1141 // ----------------------------------------------------------------------------
1142
1143 bool wxGetEnv(const wxString& var, wxString *value)
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
1158 bool wxSetEnv(const wxString& variable, const wxChar *value)
1159 {
1160 #if defined(HAVE_SETENV)
1161 return setenv(variable.mb_str(),
1162 value ? (const char *)wxString(value).mb_str()
1163 : NULL,
1164 1 /* overwrite */) == 0;
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
1183 // ----------------------------------------------------------------------------
1184 // signal handling
1185 // ----------------------------------------------------------------------------
1186
1187 #if wxUSE_ON_FATAL_EXCEPTION
1188
1189 #include <signal.h>
1190
1191 extern "C" void wxFatalSignalHandler(wxTYPE_SA_HANDLER)
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
1202 bool 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
1256 // ----------------------------------------------------------------------------
1257 // error and debug output routines (deprecated, use wxLog)
1258 // ----------------------------------------------------------------------------
1259
1260 #if WXWIN_COMPATIBILITY_2_2
1261
1262 void 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
1271 void wxError( const wxString &msg, const wxString &title )
1272 {
1273 wxFprintf( stderr, _("Error ") );
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") );
1277 }
1278
1279 void wxFatalError( const wxString &msg, const wxString &title )
1280 {
1281 wxFprintf( stderr, _("Error ") );
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") );
1285 exit(3); // the same exit code as for abort()
1286 }
1287
1288 #endif // WXWIN_COMPATIBILITY_2_2
1289