]> git.saurik.com Git - wxWidgets.git/blob - src/unix/utilsunx.cpp
(char*)(const char*)xxx.mb_str() is not a good
[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 #if wxUSE_UNICODE
257 long lRc = -1;
258 #else
259 long lRc = wxExecute(argv, flags, process);
260 #endif
261
262 // clean up
263 argc = 0;
264 while( argv[argc] )
265 delete [] argv[argc++];
266
267 return lRc;
268 }
269
270 // ----------------------------------------------------------------------------
271 // wxShell
272 // ----------------------------------------------------------------------------
273
274 static wxString wxMakeShellCommand(const wxString& command)
275 {
276 wxString cmd;
277 if ( !command )
278 {
279 // just an interactive shell
280 cmd = _T("xterm");
281 }
282 else
283 {
284 // execute command in a shell
285 cmd << _T("/bin/sh -c '") << command << _T('\'');
286 }
287
288 return cmd;
289 }
290
291 bool wxShell(const wxString& command)
292 {
293 return wxExecute(wxMakeShellCommand(command), wxEXEC_SYNC) == 0;
294 }
295
296 bool wxShell(const wxString& command, wxArrayString& output)
297 {
298 wxCHECK_MSG( !!command, FALSE, _T("can't exec shell non interactively") );
299
300 return wxExecute(wxMakeShellCommand(command), output);
301 }
302
303 // Shutdown or reboot the PC
304 bool wxShutdown(wxShutdownFlags wFlags)
305 {
306 wxChar level;
307 switch ( wFlags )
308 {
309 case wxSHUTDOWN_POWEROFF:
310 level = _T('0');
311 break;
312
313 case wxSHUTDOWN_REBOOT:
314 level = _T('6');
315 break;
316
317 default:
318 wxFAIL_MSG( _T("unknown wxShutdown() flag") );
319 return FALSE;
320 }
321
322 return system(wxString::Format(_T("init %c"), level).mb_str()) == 0;
323 }
324
325
326 #if wxUSE_GUI
327
328 void wxHandleProcessTermination(wxEndProcessData *proc_data)
329 {
330 // notify user about termination if required
331 if ( proc_data->process )
332 {
333 proc_data->process->OnTerminate(proc_data->pid, proc_data->exitcode);
334 }
335
336 // clean up
337 if ( proc_data->pid > 0 )
338 {
339 delete proc_data;
340 }
341 else
342 {
343 // let wxExecute() know that the process has terminated
344 proc_data->pid = 0;
345 }
346 }
347
348 #endif // wxUSE_GUI
349
350 // ----------------------------------------------------------------------------
351 // wxStream classes to support IO redirection in wxExecute
352 // ----------------------------------------------------------------------------
353
354 #if wxUSE_STREAMS
355
356 // ----------------------------------------------------------------------------
357 // wxProcessFileInputStream: stream for reading from a pipe
358 // ----------------------------------------------------------------------------
359
360 class wxProcessFileInputStream : public wxFileInputStream
361 {
362 public:
363 wxProcessFileInputStream(int fd) : wxFileInputStream(fd) { }
364
365 // return TRUE if we have anything to read, don't block
366 bool IsAvailable() const;
367 };
368
369 bool wxProcessFileInputStream::IsAvailable() const
370 {
371 if ( m_lasterror == wxSTREAM_EOF )
372 return TRUE;
373
374 // check if there is any input available
375 struct timeval tv;
376 tv.tv_sec = 0;
377 tv.tv_usec = 0;
378
379 const int fd = m_file->fd();
380
381 fd_set readfds;
382 FD_ZERO(&readfds);
383 FD_SET(fd, &readfds);
384 switch ( select(fd + 1, &readfds, NULL, NULL, &tv) )
385 {
386 case -1:
387 wxLogSysError(_("Impossible to get child process input"));
388 // fall through
389
390 case 0:
391 return TRUE;
392
393 default:
394 wxFAIL_MSG(_T("unexpected select() return value"));
395 // still fall through
396
397 case 1:
398 // input available
399 return TRUE;
400 }
401 }
402
403 // ----------------------------------------------------------------------------
404 // wxStreamTempInputBuffer
405 // ----------------------------------------------------------------------------
406
407 /*
408 Extract of a mail to wx-users to give the context of the problem we are
409 trying to solve here:
410
411 MC> If I run the command:
412 MC> find . -name "*.h" -exec grep linux {} \;
413 MC> in the exec sample synchronously from the 'Capture command output'
414 MC> menu, wxExecute never returns. I have to xkill it. Has anyone
415 MC> else encountered this?
416
417 Yes, I can reproduce it too.
418
419 I even think I understand why it happens: before launching the external
420 command we set up a pipe with a valid file descriptor on the reading side
421 when the output is redirected. So the subprocess happily writes to it ...
422 until the pipe buffer (which is usually quite big on Unix, I think the
423 default is 4Kb) is full. Then the writing process stops and waits until we
424 read some data from the pipe to be able to continue writing to it but we
425 never do it because we wait until it terminates to start reading and so we
426 have a classical deadlock.
427
428 Here is the fix: we now read the output as soon as it appears into a temp
429 buffer (wxStreamTempInputBuffer object) and later just stuff it back into the
430 stream when the process terminates. See supporting code in wxExecute()
431 itself as well.
432
433 Note that this is horribly inefficient for large amounts of output (count
434 the number of times we copy the data around) and so a better API is badly
435 needed!
436 */
437
438 class wxStreamTempInputBuffer
439 {
440 public:
441 wxStreamTempInputBuffer();
442
443 // call to associate a stream with this buffer, otherwise nothing happens
444 // at all
445 void Init(wxProcessFileInputStream *stream);
446
447 // check for input on our stream and cache it in our buffer if any
448 void Update();
449
450 ~wxStreamTempInputBuffer();
451
452 private:
453 // the stream we're buffering, if NULL we don't do anything at all
454 wxProcessFileInputStream *m_stream;
455
456 // the buffer of size m_size (NULL if m_size == 0)
457 void *m_buffer;
458
459 // the size of the buffer
460 size_t m_size;
461 };
462
463 wxStreamTempInputBuffer::wxStreamTempInputBuffer()
464 {
465 m_stream = NULL;
466 m_buffer = NULL;
467 m_size = 0;
468 }
469
470 void wxStreamTempInputBuffer::Init(wxProcessFileInputStream *stream)
471 {
472 m_stream = stream;
473 }
474
475 void wxStreamTempInputBuffer::Update()
476 {
477 if ( m_stream && m_stream->IsAvailable() )
478 {
479 // realloc in blocks of 4Kb: this is the default (and minimal) buffer
480 // size of the Unix pipes so it should be the optimal step
481 static const size_t incSize = 4096;
482
483 void *buf = realloc(m_buffer, m_size + incSize);
484 if ( !buf )
485 {
486 // don't read any more, we don't have enough memory to do it
487 m_stream = NULL;
488 }
489 else // got memory for the buffer
490 {
491 m_buffer = buf;
492 m_stream->Read((char *)m_buffer + m_size, incSize);
493 m_size += m_stream->LastRead();
494 }
495 }
496 }
497
498 wxStreamTempInputBuffer::~wxStreamTempInputBuffer()
499 {
500 if ( m_buffer )
501 {
502 m_stream->Ungetch(m_buffer, m_size);
503 free(m_buffer);
504 }
505 }
506
507 #endif // wxUSE_STREAMS
508
509 // ----------------------------------------------------------------------------
510 // wxPipe: this encapsulates pipe() system call
511 // ----------------------------------------------------------------------------
512
513 class wxPipe
514 {
515 public:
516 // the symbolic names for the pipe ends
517 enum Direction
518 {
519 Read,
520 Write
521 };
522
523 enum
524 {
525 INVALID_FD = -1
526 };
527
528 // default ctor doesn't do anything
529 wxPipe() { m_fds[Read] = m_fds[Write] = INVALID_FD; }
530
531 // create the pipe, return TRUE if ok, FALSE on error
532 bool Create()
533 {
534 if ( pipe(m_fds) == -1 )
535 {
536 wxLogSysError(_("Pipe creation failed"));
537
538 return FALSE;
539 }
540
541 return TRUE;
542 }
543
544 // return TRUE if we were created successfully
545 bool IsOk() const { return m_fds[Read] != INVALID_FD; }
546
547 // return the descriptor for one of the pipe ends
548 int operator[](Direction which) const
549 {
550 wxASSERT_MSG( which >= 0 && (size_t)which < WXSIZEOF(m_fds),
551 _T("invalid pipe index") );
552
553 return m_fds[which];
554 }
555
556 // detach a descriptor, meaning that the pipe dtor won't close it, and
557 // return it
558 int Detach(Direction which)
559 {
560 wxASSERT_MSG( which >= 0 && (size_t)which < WXSIZEOF(m_fds),
561 _T("invalid pipe index") );
562
563 int fd = m_fds[which];
564 m_fds[which] = INVALID_FD;
565
566 return fd;
567 }
568
569 // close the pipe descriptors
570 void Close()
571 {
572 for ( size_t n = 0; n < WXSIZEOF(m_fds); n++ )
573 {
574 if ( m_fds[n] != INVALID_FD )
575 close(m_fds[n]);
576 }
577 }
578
579 // dtor closes the pipe descriptors
580 ~wxPipe() { Close(); }
581
582 private:
583 int m_fds[2];
584 };
585
586 // ----------------------------------------------------------------------------
587 // wxExecute: the real worker function
588 // ----------------------------------------------------------------------------
589 #ifdef __VMS
590 #pragma message disable codeunreachable
591 #endif
592
593 long wxExecute(wxChar **argv,
594 int flags,
595 wxProcess *process)
596 {
597 // for the sync execution, we return -1 to indicate failure, but for async
598 // case we return 0 which is never a valid PID
599 //
600 // we define this as a macro, not a variable, to avoid compiler warnings
601 // about "ERROR_RETURN_CODE value may be clobbered by fork()"
602 #define ERROR_RETURN_CODE ((flags & wxEXEC_SYNC) ? -1 : 0)
603
604 wxCHECK_MSG( *argv, ERROR_RETURN_CODE, wxT("can't exec empty command") );
605
606 #if wxUSE_UNICODE
607 int mb_argc = 0;
608 char *mb_argv[WXEXECUTE_NARGS];
609
610 while (argv[mb_argc])
611 {
612 wxWX2MBbuf mb_arg = wxConvertWX2MB(argv[mb_argc]);
613 mb_argv[mb_argc] = strdup(mb_arg);
614 mb_argc++;
615 }
616 mb_argv[mb_argc] = (char *) NULL;
617
618 // this macro will free memory we used above
619 #define ARGS_CLEANUP \
620 for ( mb_argc = 0; mb_argv[mb_argc]; mb_argc++ ) \
621 free(mb_argv[mb_argc])
622 #else // ANSI
623 // no need for cleanup
624 #define ARGS_CLEANUP
625
626 wxChar **mb_argv = argv;
627 #endif // Unicode/ANSI
628
629 #if wxUSE_GUI
630 // create pipes
631 wxPipe pipeEndProcDetect;
632 if ( !pipeEndProcDetect.Create() )
633 {
634 wxLogError( _("Failed to execute '%s'\n"), *argv );
635
636 ARGS_CLEANUP;
637
638 return ERROR_RETURN_CODE;
639 }
640 #endif // wxUSE_GUI
641
642 // pipes for inter process communication
643 wxPipe pipeIn, // stdin
644 pipeOut, // stdout
645 pipeErr; // stderr
646
647 if ( process && process->IsRedirected() )
648 {
649 if ( !pipeIn.Create() || !pipeOut.Create() || !pipeErr.Create() )
650 {
651 wxLogError( _("Failed to execute '%s'\n"), *argv );
652
653 ARGS_CLEANUP;
654
655 return ERROR_RETURN_CODE;
656 }
657 }
658
659 // fork the process
660 #ifdef HAVE_VFORK
661 pid_t pid = vfork();
662 #else
663 pid_t pid = fork();
664 #endif
665
666 if ( pid == -1 ) // error?
667 {
668 wxLogSysError( _("Fork failed") );
669
670 ARGS_CLEANUP;
671
672 return ERROR_RETURN_CODE;
673 }
674 else if ( pid == 0 ) // we're in child
675 {
676 // These lines close the open file descriptors to to avoid any
677 // input/output which might block the process or irritate the user. If
678 // one wants proper IO for the subprocess, the right thing to do is to
679 // start an xterm executing it.
680 if ( !(flags & wxEXEC_SYNC) )
681 {
682 for ( int fd = 0; fd < FD_SETSIZE; fd++ )
683 {
684 if ( fd == pipeIn[wxPipe::Read]
685 || fd == pipeOut[wxPipe::Write]
686 || fd == pipeErr[wxPipe::Write]
687 #if wxUSE_GUI
688 || fd == pipeEndProcDetect[wxPipe::Write]
689 #endif // wxUSE_GUI
690 )
691 {
692 // don't close this one, we still need it
693 continue;
694 }
695
696 // leave stderr opened too, it won't do any harm
697 if ( fd != STDERR_FILENO )
698 close(fd);
699 }
700 }
701
702 #ifndef __VMS
703 if ( flags & wxEXEC_MAKE_GROUP_LEADER )
704 {
705 // Set process group to child process' pid. Then killing -pid
706 // of the parent will kill the process and all of its children.
707 setsid();
708 }
709 #endif // !__VMS
710
711 #if wxUSE_GUI
712 // reading side can be safely closed but we should keep the write one
713 // opened
714 pipeEndProcDetect.Detach(wxPipe::Write);
715 pipeEndProcDetect.Close();
716 #endif // wxUSE_GUI
717
718 // redirect stdin, stdout and stderr
719 if ( pipeIn.IsOk() )
720 {
721 if ( dup2(pipeIn[wxPipe::Read], STDIN_FILENO) == -1 ||
722 dup2(pipeOut[wxPipe::Write], STDOUT_FILENO) == -1 ||
723 dup2(pipeErr[wxPipe::Write], STDERR_FILENO) == -1 )
724 {
725 wxLogSysError(_("Failed to redirect child process input/output"));
726 }
727
728 pipeIn.Close();
729 pipeOut.Close();
730 pipeErr.Close();
731 }
732
733 execvp (*mb_argv, mb_argv);
734
735 // there is no return after successful exec()
736 _exit(-1);
737
738 // some compilers complain about missing return - of course, they
739 // should know that exit() doesn't return but what else can we do if
740 // they don't?
741 //
742 // and, sure enough, other compilers complain about unreachable code
743 // after exit() call, so we can just always have return here...
744 #if defined(__VMS) || defined(__INTEL_COMPILER)
745 return 0;
746 #endif
747 }
748 else // we're in parent
749 {
750 ARGS_CLEANUP;
751
752 // prepare for IO redirection
753
754 #if wxUSE_STREAMS
755 // the input buffer bufOut is connected to stdout, this is why it is
756 // called bufOut and not bufIn
757 wxStreamTempInputBuffer bufOut,
758 bufErr;
759 #endif // wxUSE_STREAMS
760
761 if ( process && process->IsRedirected() )
762 {
763 #if wxUSE_STREAMS
764 wxOutputStream *inStream =
765 new wxFileOutputStream(pipeIn.Detach(wxPipe::Write));
766
767 wxProcessFileInputStream *outStream =
768 new wxProcessFileInputStream(pipeOut.Detach(wxPipe::Read));
769
770 wxProcessFileInputStream *errStream =
771 new wxProcessFileInputStream(pipeErr.Detach(wxPipe::Read));
772
773 process->SetPipeStreams(outStream, inStream, errStream);
774
775 bufOut.Init(outStream);
776 bufErr.Init(errStream);
777 #endif // wxUSE_STREAMS
778 }
779
780 if ( pipeIn.IsOk() )
781 {
782 pipeIn.Close();
783 pipeOut.Close();
784 pipeErr.Close();
785 }
786
787 #if wxUSE_GUI && !defined(__WXMICROWIN__)
788 wxEndProcessData *data = new wxEndProcessData;
789
790 data->tag = wxAddProcessCallback
791 (
792 data,
793 pipeEndProcDetect.Detach(wxPipe::Read)
794 );
795
796 pipeEndProcDetect.Close();
797
798 if ( flags & wxEXEC_SYNC )
799 {
800 // we may have process for capturing the program output, but it's
801 // not used in wxEndProcessData in the case of sync execution
802 data->process = NULL;
803
804 // sync execution: indicate it by negating the pid
805 data->pid = -pid;
806
807 wxBusyCursor bc;
808 wxWindowDisabler wd;
809
810 // data->pid will be set to 0 from GTK_EndProcessDetector when the
811 // process terminates
812 while ( data->pid != 0 )
813 {
814 #if wxUSE_STREAMS
815 bufOut.Update();
816 bufErr.Update();
817 #endif // wxUSE_STREAMS
818
819 // give GTK+ a chance to call GTK_EndProcessDetector here and
820 // also repaint the GUI
821 wxYield();
822 }
823
824 int exitcode = data->exitcode;
825
826 delete data;
827
828 return exitcode;
829 }
830 else // async execution
831 {
832 // async execution, nothing special to do - caller will be
833 // notified about the process termination if process != NULL, data
834 // will be deleted in GTK_EndProcessDetector
835 data->process = process;
836 data->pid = pid;
837
838 return pid;
839 }
840 #else // !wxUSE_GUI
841
842 wxASSERT_MSG( flags & wxEXEC_SYNC,
843 wxT("async execution not supported yet") );
844
845 int exitcode = 0;
846 if ( waitpid(pid, &exitcode, 0) == -1 || !WIFEXITED(exitcode) )
847 {
848 wxLogSysError(_("Waiting for subprocess termination failed"));
849 }
850
851 return exitcode;
852 #endif // wxUSE_GUI
853 }
854
855 return ERROR_RETURN_CODE;
856 }
857 #ifdef __VMS
858 #pragma message enable codeunreachable
859 #endif
860
861 #undef ERROR_RETURN_CODE
862 #undef ARGS_CLEANUP
863
864 // ----------------------------------------------------------------------------
865 // file and directory functions
866 // ----------------------------------------------------------------------------
867
868 const wxChar* wxGetHomeDir( wxString *home )
869 {
870 *home = wxGetUserHome( wxString() );
871 wxString tmp;
872 if ( home->IsEmpty() )
873 *home = wxT("/");
874 #ifdef __VMS
875 tmp = *home;
876 if ( tmp.Last() != wxT(']'))
877 if ( tmp.Last() != wxT('/')) *home << wxT('/');
878 #endif
879 return home->c_str();
880 }
881
882 #if wxUSE_UNICODE
883 const wxMB2WXbuf wxGetUserHome( const wxString &user )
884 #else // just for binary compatibility -- there is no 'const' here
885 char *wxGetUserHome( const wxString &user )
886 #endif
887 {
888 struct passwd *who = (struct passwd *) NULL;
889
890 if ( !user )
891 {
892 wxChar *ptr;
893
894 if ((ptr = wxGetenv(wxT("HOME"))) != NULL)
895 {
896 return ptr;
897 }
898 if ((ptr = wxGetenv(wxT("USER"))) != NULL || (ptr = wxGetenv(wxT("LOGNAME"))) != NULL)
899 {
900 who = getpwnam(wxConvertWX2MB(ptr));
901 }
902
903 // We now make sure the the user exists!
904 if (who == NULL)
905 {
906 who = getpwuid(getuid());
907 }
908 }
909 else
910 {
911 who = getpwnam (user.mb_str());
912 }
913
914 return wxConvertMB2WX(who ? who->pw_dir : 0);
915 }
916
917 // ----------------------------------------------------------------------------
918 // network and user id routines
919 // ----------------------------------------------------------------------------
920
921 // retrieve either the hostname or FQDN depending on platform (caller must
922 // check whether it's one or the other, this is why this function is for
923 // private use only)
924 static bool wxGetHostNameInternal(wxChar *buf, int sz)
925 {
926 wxCHECK_MSG( buf, FALSE, wxT("NULL pointer in wxGetHostNameInternal") );
927
928 *buf = wxT('\0');
929
930 // we're using uname() which is POSIX instead of less standard sysinfo()
931 #if defined(HAVE_UNAME)
932 struct utsname uts;
933 bool ok = uname(&uts) != -1;
934 if ( ok )
935 {
936 wxStrncpy(buf, wxConvertMB2WX(uts.nodename), sz - 1);
937 buf[sz] = wxT('\0');
938 }
939 #elif defined(HAVE_GETHOSTNAME)
940 bool ok = gethostname(buf, sz) != -1;
941 #else // no uname, no gethostname
942 wxFAIL_MSG(wxT("don't know host name for this machine"));
943
944 bool ok = FALSE;
945 #endif // uname/gethostname
946
947 if ( !ok )
948 {
949 wxLogSysError(_("Cannot get the hostname"));
950 }
951
952 return ok;
953 }
954
955 bool wxGetHostName(wxChar *buf, int sz)
956 {
957 bool ok = wxGetHostNameInternal(buf, sz);
958
959 if ( ok )
960 {
961 // BSD systems return the FQDN, we only want the hostname, so extract
962 // it (we consider that dots are domain separators)
963 wxChar *dot = wxStrchr(buf, wxT('.'));
964 if ( dot )
965 {
966 // nuke it
967 *dot = wxT('\0');
968 }
969 }
970
971 return ok;
972 }
973
974 bool wxGetFullHostName(wxChar *buf, int sz)
975 {
976 bool ok = wxGetHostNameInternal(buf, sz);
977
978 if ( ok )
979 {
980 if ( !wxStrchr(buf, wxT('.')) )
981 {
982 struct hostent *host = gethostbyname(wxConvertWX2MB(buf));
983 if ( !host )
984 {
985 wxLogSysError(_("Cannot get the official hostname"));
986
987 ok = FALSE;
988 }
989 else
990 {
991 // the canonical name
992 wxStrncpy(buf, wxConvertMB2WX(host->h_name), sz);
993 }
994 }
995 //else: it's already a FQDN (BSD behaves this way)
996 }
997
998 return ok;
999 }
1000
1001 bool wxGetUserId(wxChar *buf, int sz)
1002 {
1003 struct passwd *who;
1004
1005 *buf = wxT('\0');
1006 if ((who = getpwuid(getuid ())) != NULL)
1007 {
1008 wxStrncpy (buf, wxConvertMB2WX(who->pw_name), sz - 1);
1009 return TRUE;
1010 }
1011
1012 return FALSE;
1013 }
1014
1015 bool wxGetUserName(wxChar *buf, int sz)
1016 {
1017 struct passwd *who;
1018
1019 *buf = wxT('\0');
1020 if ((who = getpwuid (getuid ())) != NULL)
1021 {
1022 // pw_gecos field in struct passwd is not standard
1023 #ifdef HAVE_PW_GECOS
1024 char *comma = strchr(who->pw_gecos, ',');
1025 if (comma)
1026 *comma = '\0'; // cut off non-name comment fields
1027 wxStrncpy (buf, wxConvertMB2WX(who->pw_gecos), sz - 1);
1028 #else // !HAVE_PW_GECOS
1029 wxStrncpy (buf, wxConvertMB2WX(who->pw_name), sz - 1);
1030 #endif // HAVE_PW_GECOS/!HAVE_PW_GECOS
1031 return TRUE;
1032 }
1033
1034 return FALSE;
1035 }
1036
1037 #ifndef __WXMAC__
1038 wxString wxGetOsDescription()
1039 {
1040 #ifndef WXWIN_OS_DESCRIPTION
1041 #error WXWIN_OS_DESCRIPTION should be defined in config.h by configure
1042 #else
1043 return WXWIN_OS_DESCRIPTION;
1044 #endif
1045 }
1046 #endif
1047
1048 // this function returns the GUI toolkit version in GUI programs, but OS
1049 // version in non-GUI ones
1050 #if !wxUSE_GUI
1051
1052 int wxGetOsVersion(int *majorVsn, int *minorVsn)
1053 {
1054 int major, minor;
1055 char name[256];
1056
1057 if ( sscanf(WXWIN_OS_DESCRIPTION, "%s %d.%d", name, &major, &minor) != 3 )
1058 {
1059 // unreckognized uname string format
1060 major = minor = -1;
1061 }
1062
1063 if ( majorVsn )
1064 *majorVsn = major;
1065 if ( minorVsn )
1066 *minorVsn = minor;
1067
1068 return wxUNIX;
1069 }
1070
1071 #endif // !wxUSE_GUI
1072
1073 unsigned long wxGetProcessId()
1074 {
1075 return (unsigned long)getpid();
1076 }
1077
1078 long wxGetFreeMemory()
1079 {
1080 #if defined(__LINUX__)
1081 // get it from /proc/meminfo
1082 FILE *fp = fopen("/proc/meminfo", "r");
1083 if ( fp )
1084 {
1085 long memFree = -1;
1086
1087 char buf[1024];
1088 if ( fgets(buf, WXSIZEOF(buf), fp) && fgets(buf, WXSIZEOF(buf), fp) )
1089 {
1090 long memTotal, memUsed;
1091 sscanf(buf, "Mem: %ld %ld %ld", &memTotal, &memUsed, &memFree);
1092 }
1093
1094 fclose(fp);
1095
1096 return memFree;
1097 }
1098 #elif defined(__SUN__) && defined(_SC_AVPHYS_PAGES)
1099 return sysconf(_SC_AVPHYS_PAGES)*sysconf(_SC_PAGESIZE);
1100 //#elif defined(__FREEBSD__) -- might use sysctl() to find it out, probably
1101 #endif
1102
1103 // can't find it out
1104 return -1;
1105 }
1106
1107 bool wxGetDiskSpace(const wxString& path, wxLongLong *pTotal, wxLongLong *pFree)
1108 {
1109 #if defined(HAVE_STATFS) || defined(HAVE_STATVFS)
1110 // the case to "char *" is needed for AIX 4.3
1111 wxStatFs fs;
1112 if ( statfs((char *)(const char*)path.fn_str(), &fs) != 0 )
1113 {
1114 wxLogSysError( wxT("Failed to get file system statistics") );
1115
1116 return FALSE;
1117 }
1118
1119 // under Solaris we also have to use f_frsize field instead of f_bsize
1120 // which is in general a multiple of f_frsize
1121 #ifdef HAVE_STATVFS
1122 wxLongLong blockSize = fs.f_frsize;
1123 #else // HAVE_STATFS
1124 wxLongLong blockSize = fs.f_bsize;
1125 #endif // HAVE_STATVFS/HAVE_STATFS
1126
1127 if ( pTotal )
1128 {
1129 *pTotal = wxLongLong(fs.f_blocks) * blockSize;
1130 }
1131
1132 if ( pFree )
1133 {
1134 *pFree = wxLongLong(fs.f_bavail) * blockSize;
1135 }
1136
1137 return TRUE;
1138 #else // !HAVE_STATFS && !HAVE_STATVFS
1139 return FALSE;
1140 #endif // HAVE_STATFS
1141 }
1142
1143 // ----------------------------------------------------------------------------
1144 // env vars
1145 // ----------------------------------------------------------------------------
1146
1147 bool wxGetEnv(const wxString& var, wxString *value)
1148 {
1149 // wxGetenv is defined as getenv()
1150 wxChar *p = wxGetenv(var);
1151 if ( !p )
1152 return FALSE;
1153
1154 if ( value )
1155 {
1156 *value = p;
1157 }
1158
1159 return TRUE;
1160 }
1161
1162 bool wxSetEnv(const wxString& variable, const wxChar *value)
1163 {
1164 #if defined(HAVE_SETENV)
1165 return setenv(variable.mb_str(),
1166 value ? (const char *)wxString(value).mb_str()
1167 : NULL,
1168 1 /* overwrite */) == 0;
1169 #elif defined(HAVE_PUTENV)
1170 wxString s = variable;
1171 if ( value )
1172 s << _T('=') << value;
1173
1174 // transform to ANSI
1175 const char *p = s.mb_str();
1176
1177 // the string will be free()d by libc
1178 char *buf = (char *)malloc(strlen(p) + 1);
1179 strcpy(buf, p);
1180
1181 return putenv(buf) == 0;
1182 #else // no way to set an env var
1183 return FALSE;
1184 #endif
1185 }
1186
1187 // ----------------------------------------------------------------------------
1188 // signal handling
1189 // ----------------------------------------------------------------------------
1190
1191 #if wxUSE_ON_FATAL_EXCEPTION
1192
1193 #include <signal.h>
1194
1195 extern "C" void wxFatalSignalHandler(wxTYPE_SA_HANDLER)
1196 {
1197 if ( wxTheApp )
1198 {
1199 // give the user a chance to do something special about this
1200 wxTheApp->OnFatalException();
1201 }
1202
1203 abort();
1204 }
1205
1206 bool wxHandleFatalExceptions(bool doit)
1207 {
1208 // old sig handlers
1209 static bool s_savedHandlers = FALSE;
1210 static struct sigaction s_handlerFPE,
1211 s_handlerILL,
1212 s_handlerBUS,
1213 s_handlerSEGV;
1214
1215 bool ok = TRUE;
1216 if ( doit && !s_savedHandlers )
1217 {
1218 // install the signal handler
1219 struct sigaction act;
1220
1221 // some systems extend it with non std fields, so zero everything
1222 memset(&act, 0, sizeof(act));
1223
1224 act.sa_handler = wxFatalSignalHandler;
1225 sigemptyset(&act.sa_mask);
1226 act.sa_flags = 0;
1227
1228 ok &= sigaction(SIGFPE, &act, &s_handlerFPE) == 0;
1229 ok &= sigaction(SIGILL, &act, &s_handlerILL) == 0;
1230 ok &= sigaction(SIGBUS, &act, &s_handlerBUS) == 0;
1231 ok &= sigaction(SIGSEGV, &act, &s_handlerSEGV) == 0;
1232 if ( !ok )
1233 {
1234 wxLogDebug(_T("Failed to install our signal handler."));
1235 }
1236
1237 s_savedHandlers = TRUE;
1238 }
1239 else if ( s_savedHandlers )
1240 {
1241 // uninstall the signal handler
1242 ok &= sigaction(SIGFPE, &s_handlerFPE, NULL) == 0;
1243 ok &= sigaction(SIGILL, &s_handlerILL, NULL) == 0;
1244 ok &= sigaction(SIGBUS, &s_handlerBUS, NULL) == 0;
1245 ok &= sigaction(SIGSEGV, &s_handlerSEGV, NULL) == 0;
1246 if ( !ok )
1247 {
1248 wxLogDebug(_T("Failed to uninstall our signal handler."));
1249 }
1250
1251 s_savedHandlers = FALSE;
1252 }
1253 //else: nothing to do
1254
1255 return ok;
1256 }
1257
1258 #endif // wxUSE_ON_FATAL_EXCEPTION
1259
1260 // ----------------------------------------------------------------------------
1261 // error and debug output routines (deprecated, use wxLog)
1262 // ----------------------------------------------------------------------------
1263
1264 #if WXWIN_COMPATIBILITY_2_2
1265
1266 void wxDebugMsg( const char *format, ... )
1267 {
1268 va_list ap;
1269 va_start( ap, format );
1270 vfprintf( stderr, format, ap );
1271 fflush( stderr );
1272 va_end(ap);
1273 }
1274
1275 void wxError( const wxString &msg, const wxString &title )
1276 {
1277 wxFprintf( stderr, _("Error ") );
1278 if (!title.IsNull()) wxFprintf( stderr, wxT("%s "), WXSTRINGCAST(title) );
1279 if (!msg.IsNull()) wxFprintf( stderr, wxT(": %s"), WXSTRINGCAST(msg) );
1280 wxFprintf( stderr, wxT(".\n") );
1281 }
1282
1283 void wxFatalError( const wxString &msg, const wxString &title )
1284 {
1285 wxFprintf( stderr, _("Error ") );
1286 if (!title.IsNull()) wxFprintf( stderr, wxT("%s "), WXSTRINGCAST(title) );
1287 if (!msg.IsNull()) wxFprintf( stderr, wxT(": %s"), WXSTRINGCAST(msg) );
1288 wxFprintf( stderr, wxT(".\n") );
1289 exit(3); // the same exit code as for abort()
1290 }
1291
1292 #endif // WXWIN_COMPATIBILITY_2_2
1293