]>
git.saurik.com Git - wxWidgets.git/blob - src/unix/utilsunx.cpp
3b09340becb2edae82448469af9a0f83d3973a86
   1 ///////////////////////////////////////////////////////////////////////////// 
   3 // Purpose:     generic Unix implementation of many wx functions 
   4 // Author:      Vadim Zeitlin 
   6 // Copyright:   (c) 1998 Robert Roebling, Vadim Zeitlin 
   7 // Licence:     wxWindows licence 
   8 ///////////////////////////////////////////////////////////////////////////// 
  10 // ============================================================================ 
  12 // ============================================================================ 
  14 // ---------------------------------------------------------------------------- 
  16 // ---------------------------------------------------------------------------- 
  19 #include "wx/string.h" 
  25 #include "wx/process.h" 
  26 #include "wx/thread.h" 
  29     #include "wx/unix/execute.h" 
  36 #include <sys/types.h> 
  43 #include <fcntl.h>          // for O_WRONLY and friends 
  44 #include <time.h>           // nanosleep() and/or usleep() 
  45 #include <ctype.h>          // isspace() 
  46 #include <sys/time.h>       // needed for FD_SETSIZE 
  49     #include <sys/utsname.h> // for uname() 
  52 // ---------------------------------------------------------------------------- 
  53 // conditional compilation 
  54 // ---------------------------------------------------------------------------- 
  56 // many versions of Unices have this function, but it is not defined in system 
  57 // headers - please add your system here if it is the case for your OS. 
  58 // SunOS < 5.6 (i.e. Solaris < 2.6) and DG-UX are like this. 
  59 #if !defined(HAVE_USLEEP) && \ 
  60     (defined(__SUN__) && !defined(__SunOs_5_6) && \ 
  61                          !defined(__SunOs_5_7) && !defined(__SUNPRO_CC)) || \ 
  62      defined(__osf__) || defined(__EMX__) 
  66             int usleep(unsigned int usec
); 
  69                 /* I copied this from the XFree86 diffs. AV. */ 
  70                 #define INCL_DOSPROCESS 
  72                 inline void usleep(unsigned long delay
) 
  74                     DosSleep(delay 
? (delay
/1000l) : 1l); 
  77                 void usleep(unsigned long usec
); 
  79         #endif // Sun/EMX/Something else 
  83 #endif // Unices without usleep() 
  85 // ============================================================================ 
  87 // ============================================================================ 
  89 // ---------------------------------------------------------------------------- 
  91 // ---------------------------------------------------------------------------- 
  93 void wxSleep(int nSecs
) 
  98 void wxUsleep(unsigned long milliseconds
) 
 100 #if defined(HAVE_NANOSLEEP) 
 102     tmReq
.tv_sec 
= (time_t)(milliseconds 
/ 1000); 
 103     tmReq
.tv_nsec 
= (milliseconds 
% 1000) * 1000 * 1000; 
 105     // we're not interested in remaining time nor in return value 
 106     (void)nanosleep(&tmReq
, (timespec 
*)NULL
); 
 107 #elif defined(HAVE_USLEEP) 
 108     // uncomment this if you feel brave or if you are sure that your version 
 109     // of Solaris has a safe usleep() function but please notice that usleep() 
 110     // is known to lead to crashes in MT programs in Solaris 2.[67] and is not 
 111     // documented as MT-Safe 
 112     #if defined(__SUN__) && wxUSE_THREADS 
 113         #error "usleep() cannot be used in MT programs under Solaris." 
 116     usleep(milliseconds 
* 1000); // usleep(3) wants microseconds 
 117 #elif defined(HAVE_SLEEP) 
 118     // under BeOS sleep() takes seconds (what about other platforms, if any?) 
 119     sleep(milliseconds 
* 1000); 
 120 #else // !sleep function 
 121     #error "usleep() or nanosleep() function required for wxUsleep" 
 122 #endif // sleep function 
 125 // ---------------------------------------------------------------------------- 
 126 // process management 
 127 // ---------------------------------------------------------------------------- 
 129 int wxKill(long pid
, wxSignal sig
) 
 131     return kill((pid_t
)pid
, (int)sig
); 
 134 #define WXEXECUTE_NARGS   127 
 136 long wxExecute( const wxString
& command
, bool sync
, wxProcess 
*process 
) 
 138     wxCHECK_MSG( !command
.IsEmpty(), 0, wxT("can't exec empty command") ); 
 141     wxChar 
*argv
[WXEXECUTE_NARGS
]; 
 143     const wxChar 
*cptr 
= command
.c_str(); 
 144     wxChar quotechar 
= wxT('\0'); // is arg quoted? 
 145     bool escaped 
= FALSE
; 
 147     // split the command line in arguments 
 151         quotechar 
= wxT('\0'); 
 153         // eat leading whitespace: 
 154         while ( wxIsspace(*cptr
) ) 
 157         if ( *cptr 
== wxT('\'') || *cptr 
== wxT('"') ) 
 162             if ( *cptr 
== wxT('\\') && ! escaped 
) 
 169             // all other characters: 
 173             // have we reached the end of the argument? 
 174             if ( (*cptr 
== quotechar 
&& ! escaped
) 
 175                  || (quotechar 
== wxT('\0') && wxIsspace(*cptr
)) 
 176                  || *cptr 
== wxT('\0') ) 
 178                 wxASSERT_MSG( argc 
< WXEXECUTE_NARGS
, 
 179                               wxT("too many arguments in wxExecute") ); 
 181                 argv
[argc
] = new wxChar
[argument
.length() + 1]; 
 182                 wxStrcpy(argv
[argc
], argument
.c_str()); 
 185                 // if not at end of buffer, swallow last character: 
 189                 break; // done with this one, start over 
 195     // do execute the command 
 196     long lRc 
= wxExecute(argv
, sync
, process
); 
 201         delete [] argv
[argc
++]; 
 206 bool wxShell(const wxString
& command
) 
 210         cmd
.Printf(wxT("xterm -e %s"), command
.c_str()); 
 214     return wxExecute(cmd
) != 0; 
 219 void wxHandleProcessTermination(wxEndProcessData 
*proc_data
) 
 221     int pid 
= (proc_data
->pid 
> 0) ? proc_data
->pid 
: -(proc_data
->pid
); 
 223     // waitpid is POSIX so should be available everywhere, however on older 
 224     // systems wait() might be used instead in a loop (until the right pid 
 229     // wait for child termination and if waitpid() was interrupted, try again 
 232        rc 
= waitpid(pid
, &status
, 0); 
 234     while ( rc 
== -1 && errno 
== EINTR 
); 
 237     if( rc 
== -1 || ! (WIFEXITED(status
) || WIFSIGNALED(status
)) ) 
 239        wxLogSysError(_("Waiting for subprocess termination failed")); 
 240        /* AFAIK, this can only happen if something went wrong within 
 241           wxGTK, i.e. due to a race condition or some serious bug. 
 242           After having fixed the order of statements in 
 243           GTK_EndProcessDetector(). (KB) 
 248         // notify user about termination if required 
 249         if (proc_data
->process
) 
 251             proc_data
->process
->OnTerminate(proc_data
->pid
, 
 252                                             WEXITSTATUS(status
)); 
 255         if ( proc_data
->pid 
> 0 ) 
 261            // wxExecute() will know about it 
 262            proc_data
->exitcode 
= status
; 
 272     #define WXUNUSED_UNLESS_GUI(p)  p 
 274     #define WXUNUSED_UNLESS_GUI(p) 
 277 long wxExecute(wxChar 
**argv
, 
 279                wxProcess 
* WXUNUSED_UNLESS_GUI(process
)) 
 281     wxCHECK_MSG( *argv
, 0, wxT("can't exec empty command") ); 
 285     char *mb_argv
[WXEXECUTE_NARGS
]; 
 287     while (argv
[mb_argc
]) 
 289       wxWX2MBbuf mb_arg 
= wxConvertWX2MB(argv
[mb_argc
]); 
 290       mb_argv
[mb_argc
] = strdup(mb_arg
); 
 293     mb_argv
[mb_argc
] = (char *) NULL
; 
 295     // this macro will free memory we used above 
 296     #define ARGS_CLEANUP                                 \ 
 297         for ( mb_argc = 0; mb_argv[mb_argc]; mb_argc++ ) \ 
 298             free(mb_argv[mb_argc]) 
 300     // no need for cleanup 
 303     wxChar 
**mb_argv 
= argv
; 
 304 #endif // Unicode/ANSI 
 308     int end_proc_detect
[2]; 
 309     if (pipe(end_proc_detect
) == -1) 
 311         wxLogSysError( _("Pipe creation failed") ); 
 327         wxLogSysError( _("Fork failed") ); 
 337         close(end_proc_detect
[0]); // close reading side 
 340         // These three lines close the open file descriptors to to avoid any 
 341         // input/output which might block the process or irritate the user. If 
 342         // one wants proper IO for the subprocess, the right thing to do is 
 343         // to start an xterm executing it. 
 346             // leave stderr opened, it won't do any hurm 
 347             for ( int fd 
= 0; fd 
< FD_SETSIZE
; fd
++ ) 
 350                 if ( fd 
== end_proc_detect
[1] ) 
 354                 if ( fd 
!= STDERR_FILENO 
) 
 360         close(STDERR_FILENO
); 
 362         // some programs complain about stderr not being open, so redirect 
 364         open("/dev/null", O_RDONLY
);  // stdin 
 365         open("/dev/null", O_WRONLY
);  // stdout 
 366         open("/dev/null", O_WRONLY
);  // stderr 
 369         execvp (*mb_argv
, mb_argv
); 
 371         // there is no return after successful exec() 
 372         wxFprintf(stderr
, _("Can't execute '%s'\n"), *argv
); 
 379         wxEndProcessData 
*data 
= new wxEndProcessData
; 
 385             wxASSERT_MSG( !process
, wxT("wxProcess param ignored for sync exec") ); 
 386             data
->process 
= NULL
; 
 388             // sync execution: indicate it by negating the pid 
 390             data
->tag 
= wxAddProcessCallback(data
, end_proc_detect
[0]); 
 392             close(end_proc_detect
[1]); // close writing side 
 394             // it will be set to 0 from GTK_EndProcessDetector 
 395             while (data
->pid 
!= 0) 
 398             int exitcode 
= data
->exitcode
; 
 406             // async execution, nothing special to do - caller will be 
 407             // notified about the process termination if process != NULL, data 
 408             // will be deleted in GTK_EndProcessDetector 
 409             data
->process 
= process
; 
 411             data
->tag 
= wxAddProcessCallback(data
, end_proc_detect
[0]); 
 413             close(end_proc_detect
[1]); // close writing side 
 418         wxASSERT_MSG( sync
, wxT("async execution not supported yet") ); 
 421         if ( waitpid(pid
, &exitcode
, 0) == -1 || !WIFEXITED(exitcode
) ) 
 423             wxLogSysError(_("Waiting for subprocess termination failed")); 
 434 // ---------------------------------------------------------------------------- 
 435 // file and directory functions 
 436 // ---------------------------------------------------------------------------- 
 438 const wxChar
* wxGetHomeDir( wxString 
*home  
) 
 440     *home 
= wxGetUserHome( wxString() ); 
 441     if ( home
->IsEmpty() ) 
 444     return home
->c_str(); 
 448 const wxMB2WXbuf 
wxGetUserHome( const wxString 
&user 
) 
 449 #else // just for binary compatibility -- there is no 'const' here 
 450 char *wxGetUserHome( const wxString 
&user 
) 
 453     struct passwd 
*who 
= (struct passwd 
*) NULL
; 
 459         if ((ptr 
= wxGetenv(wxT("HOME"))) != NULL
) 
 463         if ((ptr 
= wxGetenv(wxT("USER"))) != NULL 
|| (ptr 
= wxGetenv(wxT("LOGNAME"))) != NULL
) 
 465             who 
= getpwnam(wxConvertWX2MB(ptr
)); 
 468         // We now make sure the the user exists! 
 471             who 
= getpwuid(getuid()); 
 476       who 
= getpwnam (user
.mb_str()); 
 479     return wxConvertMB2WX(who 
? who
->pw_dir 
: 0); 
 482 // ---------------------------------------------------------------------------- 
 483 // network and user id routines 
 484 // ---------------------------------------------------------------------------- 
 486 // retrieve either the hostname or FQDN depending on platform (caller must 
 487 // check whether it's one or the other, this is why this function is for 
 489 static bool wxGetHostNameInternal(wxChar 
*buf
, int sz
) 
 491     wxCHECK_MSG( buf
, FALSE
, wxT("NULL pointer in wxGetHostNameInternal") ); 
 495     // we're using uname() which is POSIX instead of less standard sysinfo() 
 496 #if defined(HAVE_UNAME) 
 498     bool ok 
= uname(&uts
) != -1; 
 501         wxStrncpy(buf
, wxConvertMB2WX(uts
.nodename
), sz 
- 1); 
 504 #elif defined(HAVE_GETHOSTNAME) 
 505     bool ok 
= gethostname(buf
, sz
) != -1; 
 506 #else // no uname, no gethostname 
 507     wxFAIL_MSG(wxT("don't know host name for this machine")); 
 510 #endif // uname/gethostname 
 514         wxLogSysError(_("Cannot get the hostname")); 
 520 bool wxGetHostName(wxChar 
*buf
, int sz
) 
 522     bool ok 
= wxGetHostNameInternal(buf
, sz
); 
 526         // BSD systems return the FQDN, we only want the hostname, so extract 
 527         // it (we consider that dots are domain separators) 
 528         wxChar 
*dot 
= wxStrchr(buf
, wxT('.')); 
 539 bool wxGetFullHostName(wxChar 
*buf
, int sz
) 
 541     bool ok 
= wxGetHostNameInternal(buf
, sz
); 
 545         if ( !wxStrchr(buf
, wxT('.')) ) 
 547             struct hostent 
*host 
= gethostbyname(wxConvertWX2MB(buf
)); 
 550                 wxLogSysError(_("Cannot get the official hostname")); 
 556                 // the canonical name 
 557                 wxStrncpy(buf
, wxConvertMB2WX(host
->h_name
), sz
); 
 560         //else: it's already a FQDN (BSD behaves this way) 
 566 bool wxGetUserId(wxChar 
*buf
, int sz
) 
 571     if ((who 
= getpwuid(getuid ())) != NULL
) 
 573         wxStrncpy (buf
, wxConvertMB2WX(who
->pw_name
), sz 
- 1); 
 580 bool wxGetUserName(wxChar 
*buf
, int sz
) 
 585     if ((who 
= getpwuid (getuid ())) != NULL
) 
 587         // pw_gecos field in struct passwd is not standard 
 589        char *comma 
= strchr(who
->pw_gecos
, ','); 
 591            *comma 
= '\0'; // cut off non-name comment fields 
 592        wxStrncpy (buf
, wxConvertMB2WX(who
->pw_gecos
), sz 
- 1); 
 593 #else // !HAVE_PW_GECOS 
 594        wxStrncpy (buf
, wxConvertMB2WX(who
->pw_name
), sz 
- 1); 
 595 #endif // HAVE_PW_GECOS/!HAVE_PW_GECOS 
 602 wxString 
wxGetOsDescription() 
 604 #ifndef WXWIN_OS_DESCRIPTION 
 605     #error WXWIN_OS_DESCRIPTION should be defined in config.h by configure 
 607     return WXWIN_OS_DESCRIPTION
; 
 611 // ---------------------------------------------------------------------------- 
 612 // error and debug output routines (deprecated, use wxLog) 
 613 // ---------------------------------------------------------------------------- 
 615 void wxDebugMsg( const char *format
, ... ) 
 618   va_start( ap
, format 
); 
 619   vfprintf( stderr
, format
, ap 
); 
 624 void wxError( const wxString 
&msg
, const wxString 
&title 
) 
 626   wxFprintf( stderr
, _("Error ") ); 
 627   if (!title
.IsNull()) wxFprintf( stderr
, wxT("%s "), WXSTRINGCAST(title
) ); 
 628   if (!msg
.IsNull()) wxFprintf( stderr
, wxT(": %s"), WXSTRINGCAST(msg
) ); 
 629   wxFprintf( stderr
, wxT(".\n") ); 
 632 void wxFatalError( const wxString 
&msg
, const wxString 
&title 
) 
 634   wxFprintf( stderr
, _("Error ") ); 
 635   if (!title
.IsNull()) wxFprintf( stderr
, wxT("%s "), WXSTRINGCAST(title
) ); 
 636   if (!msg
.IsNull()) wxFprintf( stderr
, wxT(": %s"), WXSTRINGCAST(msg
) ); 
 637   wxFprintf( stderr
, wxT(".\n") ); 
 638   exit(3); // the same exit code as for abort()