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" 
  27 #include "wx/unix/execute.h" 
  33 #include <sys/types.h> 
  40 #include <fcntl.h>          // for O_WRONLY and friends 
  41 #include <time.h>           // nanosleep() and/or usleep() 
  42 #include <ctype.h>          // isspace() 
  44 // JACS: needed for FD_SETSIZE 
  48     #include <sys/utsname.h> // for uname() 
  51 // ---------------------------------------------------------------------------- 
  52 // conditional compilation 
  53 // ---------------------------------------------------------------------------- 
  55 // many versions of Unices have this function, but it is not defined in system 
  56 // headers - please add your system here if it is the case for your OS. 
  57 // SunOS < 5.6 (i.e. Solaris < 2.6) and DG-UX are like this. 
  58 #if !defined(HAVE_USLEEP) && \ 
  59     (defined(__SUN__) && !defined(__SunOs_5_6) && \ 
  60                          !defined(__SunOs_5_7) && !defined(__SUNPRO_CC)) || \ 
  61      defined(__osf__) || defined(__EMX__) 
  65             int usleep(unsigned int usec
); 
  68             /* I copied this from the XFree86 diffs. AV. */ 
  69             #define INCL_DOSPROCESS 
  71             void usleep(unsigned long delay
) 
  73                 DosSleep(delay 
? (delay
/1000l) : 1l); 
  76             void usleep(unsigned long usec
); 
  78         #endif // Sun/EMX/Something else 
  81 #endif // Unices without usleep() 
  83 // ============================================================================ 
  85 // ============================================================================ 
  87 // ---------------------------------------------------------------------------- 
  89 // ---------------------------------------------------------------------------- 
  91 void wxSleep(int nSecs
) 
  96 void wxUsleep(unsigned long milliseconds
) 
 100     tmReq
.tv_sec 
= milliseconds 
/ 1000; 
 101     tmReq
.tv_nsec 
= (milliseconds 
% 1000) * 1000 * 1000; 
 103     // we're not interested in remaining time nor in return value 
 104     (void)nanosleep(&tmReq
, (timespec 
*)NULL
); 
 106     // uncomment this if you feel brave or if you are sure that your version 
 107     // of Solaris has a safe usleep() function but please notice that usleep() 
 108     // is known to lead to crashes in MT programs in Solaris 2.[67] and is not 
 109     // documented as MT-Safe 
 110     #if defined(__SUN__) && wxUSE_THREADS 
 111         #error "usleep() cannot be used in MT programs under Solaris." 
 114     usleep(milliseconds 
* 1000); // usleep(3) wants microseconds 
 115 #else // !sleep function 
 116     #error "usleep() or nanosleep() function required for wxUsleep" 
 117 #endif // sleep function 
 120 // ---------------------------------------------------------------------------- 
 121 // process management 
 122 // ---------------------------------------------------------------------------- 
 124 int wxKill(long pid
, wxSignal sig
) 
 126     return kill(pid
, (int)sig
); 
 129 #define WXEXECUTE_NARGS   127 
 131 long wxExecute( const wxString
& command
, bool sync
, wxProcess 
*process 
) 
 133     wxCHECK_MSG( !command
.IsEmpty(), 0, _T("can't exec empty command") ); 
 136     wxChar 
*argv
[WXEXECUTE_NARGS
]; 
 138     const wxChar 
*cptr 
= command
.c_str(); 
 139     wxChar quotechar 
= _T('\0'); // is arg quoted? 
 140     bool escaped 
= FALSE
; 
 142     // split the command line in arguments 
 146         quotechar 
= _T('\0'); 
 148         // eat leading whitespace: 
 149         while ( wxIsspace(*cptr
) ) 
 152         if ( *cptr 
== _T('\'') || *cptr 
== _T('"') ) 
 157             if ( *cptr 
== _T('\\') && ! escaped 
) 
 164             // all other characters: 
 168             // have we reached the end of the argument? 
 169             if ( (*cptr 
== quotechar 
&& ! escaped
) 
 170                  || (quotechar 
== _T('\0') && wxIsspace(*cptr
)) 
 171                  || *cptr 
== _T('\0') ) 
 173                 wxASSERT_MSG( argc 
< WXEXECUTE_NARGS
, 
 174                               _T("too many arguments in wxExecute") ); 
 176                 argv
[argc
] = new wxChar
[argument
.length() + 1]; 
 177                 wxStrcpy(argv
[argc
], argument
.c_str()); 
 180                 // if not at end of buffer, swallow last character: 
 184                 break; // done with this one, start over 
 190     // do execute the command 
 191     long lRc 
= wxExecute(argv
, sync
, process
); 
 196         delete [] argv
[argc
++]; 
 201 bool wxShell(const wxString
& command
) 
 205         cmd
.Printf(_T("xterm -e %s"), command
.c_str()); 
 209     return wxExecute(cmd
) != 0; 
 212 void wxHandleProcessTermination(wxEndProcessData 
*proc_data
) 
 214     int pid 
= (proc_data
->pid 
> 0) ? proc_data
->pid 
: -(proc_data
->pid
); 
 216     // waitpid is POSIX so should be available everywhere, however on older 
 217     // systems wait() might be used instead in a loop (until the right pid 
 220     if ( waitpid(pid
, &status
, 0) == -1 || !WIFEXITED(status
) ) 
 222         wxLogSysError(_("Waiting for subprocess termination failed")); 
 226         // notify user about termination if required 
 227         if (proc_data
->process
) 
 229             proc_data
->process
->OnTerminate(proc_data
->pid
, 
 230                                             WEXITSTATUS(status
)); 
 235     if ( proc_data
->pid 
> 0 ) 
 241         // wxExecute() will know about it 
 242         proc_data
->exitcode 
= status
; 
 248 long wxExecute( wxChar 
**argv
, bool sync
, wxProcess 
*process 
) 
 250     wxCHECK_MSG( *argv
, 0, _T("can't exec empty command") ); 
 252     int end_proc_detect
[2]; 
 255     char *mb_argv
[WXEXECUTE_NARGS
]; 
 257     while (argv
[mb_argc
]) { 
 258       wxWX2MBbuf mb_arg 
= wxConvCurrent
->cWX2MB(argv
[mb_argc
]); 
 259       mb_argv
[mb_argc
] = strdup(mb_arg
); 
 262     mb_argv
[mb_argc
] = (char *) NULL
; 
 264     wxChar 
**mb_argv 
= argv
; 
 268     if (pipe(end_proc_detect
) == -1) 
 270         wxLogSysError( _("Pipe creation failed") ); 
 273         while (mb_argv
[mb_argc
]) 
 274           free(mb_argv
[mb_argc
++]); 
 287         wxLogSysError( _("Fork failed") ); 
 290         while (mb_argv
[mb_argc
]) 
 291           free(mb_argv
[mb_argc
++]); 
 298         close(end_proc_detect
[0]); // close reading side 
 300         // These three lines close the open file descriptors to to avoid any 
 301         // input/output which might block the process or irritate the user. If 
 302         // one wants proper IO for the subprocess, the right thing to do is 
 303         // to start an xterm executing it. 
 306             // leave stderr opened, it won't do any hurm 
 307             for ( int fd 
= 0; fd 
< FD_SETSIZE
; fd
++ ) 
 309                 if ( fd 
!= end_proc_detect
[1] && fd 
!= STDERR_FILENO 
) 
 315         close(STDERR_FILENO
); 
 317         // some programs complain about stderr not being open, so redirect 
 319         open("/dev/null", O_RDONLY
);  // stdin 
 320         open("/dev/null", O_WRONLY
);  // stdout 
 321         open("/dev/null", O_WRONLY
);  // stderr 
 324         execvp (*mb_argv
, mb_argv
); 
 326         // there is no return after successful exec() 
 327         wxFprintf(stderr
, _("Can't execute '%s'\n"), *argv
); 
 334         close(end_proc_detect
[1]); // close writing side 
 336         wxEndProcessData 
*data 
= new wxEndProcessData
; 
 337         data
->tag 
= wxAddProcessCallback(data
, end_proc_detect
[0]); 
 341         while (mb_argv
[mb_argc
]) 
 342           free(mb_argv
[mb_argc
++]); 
 347             wxASSERT_MSG( !process
, _T("wxProcess param ignored for sync exec") ); 
 348             data
->process 
= NULL
; 
 350             // sync execution: indicate it by negating the pid 
 353             // it will be set to 0 from GTK_EndProcessDetector 
 354             while (data
->pid 
!= 0) 
 357             int exitcode 
= data
->exitcode
; 
 365             // async execution, nothing special to do - caller will be 
 366             // notified about the process terminationif process != NULL, data 
 367             // will be deleted in GTK_EndProcessDetector 
 368             data
->process 
= process
; 
 376 // ---------------------------------------------------------------------------- 
 377 // file and directory functions 
 378 // ---------------------------------------------------------------------------- 
 380 const wxChar
* wxGetHomeDir( wxString 
*home  
) 
 382     *home 
= wxGetUserHome( wxString() ); 
 383     if ( home
->IsEmpty() ) 
 386     return home
->c_str(); 
 390 const wxMB2WXbuf 
wxGetUserHome( const wxString 
&user 
) 
 391 #else // just for binary compatibility 
 392 char *wxGetUserHome( const wxString 
&user 
) 
 395     struct passwd 
*who 
= (struct passwd 
*) NULL
; 
 399         register wxChar 
*ptr
; 
 401         if ((ptr 
= wxGetenv(_T("HOME"))) != NULL
) 
 405         if ((ptr 
= wxGetenv(_T("USER"))) != NULL 
|| (ptr 
= wxGetenv(_T("LOGNAME"))) != NULL
) 
 407             who 
= getpwnam(wxConvCurrent
->cWX2MB(ptr
)); 
 410         // We now make sure the the user exists! 
 413             who 
= getpwuid(getuid()); 
 418       who 
= getpwnam (user
.mb_str()); 
 422     return who 
? wxConvCurrent
->cMB2WX(who
->pw_dir
) : (wxMB2WXbuf
)((wxChar
*)NULL
); 
 424     return who 
? who
->pw_dir 
: ((char*)NULL
); 
 428 // ---------------------------------------------------------------------------- 
 429 // network and user id routines 
 430 // ---------------------------------------------------------------------------- 
 432 // retrieve either the hostname or FQDN depending on platform (caller must 
 433 // check whether it's one or the other, this is why this function is for 
 435 static bool wxGetHostNameInternal(wxChar 
*buf
, int sz
) 
 437     wxCHECK_MSG( buf
, FALSE
, _T("NULL pointer in wxGetHostNameInternal") ); 
 441     // we're using uname() which is POSIX instead of less standard sysinfo() 
 442 #if defined(HAVE_UNAME) 
 444     bool ok 
= uname(&uts
) != -1; 
 447         wxStrncpy(buf
, wxConvCurrent
->cMB2WX(uts
.nodename
), sz 
- 1); 
 450 #elif defined(HAVE_GETHOSTNAME) 
 451     bool ok 
= gethostname(buf
, sz
) != -1; 
 452 #else // no uname, no gethostname 
 453     wxFAIL_MSG(_T("don't know host name for this machine")); 
 456 #endif // uname/gethostname 
 460         wxLogSysError(_("Cannot get the hostname")); 
 466 bool wxGetHostName(wxChar 
*buf
, int sz
) 
 468     bool ok 
= wxGetHostNameInternal(buf
, sz
); 
 472         // BSD systems return the FQDN, we only want the hostname, so extract 
 473         // it (we consider that dots are domain separators) 
 474         wxChar 
*dot 
= wxStrchr(buf
, _T('.')); 
 485 bool wxGetFullHostName(wxChar 
*buf
, int sz
) 
 487     bool ok 
= wxGetHostNameInternal(buf
, sz
); 
 491         if ( !wxStrchr(buf
, _T('.')) ) 
 493             struct hostent 
*host 
= gethostbyname(wxConvCurrent
->cWX2MB(buf
)); 
 496                 wxLogSysError(_("Cannot get the official hostname")); 
 502                 // the canonical name 
 503                 wxStrncpy(buf
, wxConvCurrent
->cMB2WX(host
->h_name
), sz
); 
 506         //else: it's already a FQDN (BSD behaves this way) 
 512 bool wxGetUserId(wxChar 
*buf
, int sz
) 
 517     if ((who 
= getpwuid(getuid ())) != NULL
) 
 519         wxStrncpy (buf
, wxConvCurrent
->cMB2WX(who
->pw_name
), sz 
- 1); 
 526 bool wxGetUserName(wxChar 
*buf
, int sz
) 
 532     if ((who 
= getpwuid (getuid ())) != NULL
) { 
 533        comma 
= strchr(who
->pw_gecos
, ','); 
 535            *comma 
= '\0'; // cut off non-name comment fields 
 536        wxStrncpy (buf
, wxConvCurrent
->cMB2WX(who
->pw_gecos
), sz 
- 1); 
 543 // ---------------------------------------------------------------------------- 
 544 // error and debug output routines (deprecated, use wxLog) 
 545 // ---------------------------------------------------------------------------- 
 547 void wxDebugMsg( const char *format
, ... ) 
 550   va_start( ap
, format 
); 
 551   vfprintf( stderr
, format
, ap 
); 
 556 void wxError( const wxString 
&msg
, const wxString 
&title 
) 
 558   wxFprintf( stderr
, _("Error ") ); 
 559   if (!title
.IsNull()) wxFprintf( stderr
, _T("%s "), WXSTRINGCAST(title
) ); 
 560   if (!msg
.IsNull()) wxFprintf( stderr
, _T(": %s"), WXSTRINGCAST(msg
) ); 
 561   wxFprintf( stderr
, _T(".\n") ); 
 564 void wxFatalError( const wxString 
&msg
, const wxString 
&title 
) 
 566   wxFprintf( stderr
, _("Error ") ); 
 567   if (!title
.IsNull()) wxFprintf( stderr
, _T("%s "), WXSTRINGCAST(title
) ); 
 568   if (!msg
.IsNull()) wxFprintf( stderr
, _T(": %s"), WXSTRINGCAST(msg
) ); 
 569   wxFprintf( stderr
, _T(".\n") ); 
 570   exit(3); // the same exit code as for abort() 
 573 // ---------------------------------------------------------------------------- 
 574 // font-related functions 
 575 // ---------------------------------------------------------------------------- 
 577 // define the functions to create and destroy native fonts for this toolkit 
 579     static inline wxNativeFont 
wxLoadFont(const wxString
& fontSpec
) 
 581         return XLoadQueryFont((Display 
*)wxGetDisplay(), fontSpec
); 
 584     static inline void wxFreeFont(wxNativeFont font
) 
 586         XFreeFont((Display 
*)wxGetDisplay(), font
); 
 588 #elif defined(__WXGTK__) 
 589     static inline wxNativeFont 
wxLoadFont(const wxString
& fontSpec
) 
 591         return gdk_font_load( wxConvCurrent
->cWX2MB(fontSpec
) ); 
 594     static inline void wxFreeFont(wxNativeFont font
) 
 596         gdk_font_unref(font
); 
 599     #error "Unknown GUI toolkit" 
 602 // returns TRUE if there are any fonts matching this font spec 
 603 static bool wxTestFontSpec(const wxString
& fontspec
) 
 605     wxNativeFont test 
= wxLoadFont(fontspec
); 
 618 // TODO encoding test logic should be moved to wxLoadQueryNearestFont() 
 619 static wxNativeFont 
wxLoadQueryFont(int pointSize
, 
 623                                     bool WXUNUSED(underlined
), 
 624                                     const wxString 
&facename
, 
 625                                     wxFontEncoding encoding 
) 
 630         case wxDECORATIVE
: xfamily 
= _T("lucida"); break; 
 631         case wxROMAN
:      xfamily 
= _T("times");  break; 
 632         case wxMODERN
:     xfamily 
= _T("courier"); break; 
 633         case wxSWISS
:      xfamily 
= _T("helvetica"); break; 
 634         case wxTELETYPE
:   xfamily 
= _T("lucidatypewriter"); break; 
 635         case wxSCRIPT
:     xfamily 
= _T("utopia"); break; 
 636         default:           xfamily 
= _T("*"); 
 640     if (!facename
.IsEmpty()) 
 642         fontSpec
.Printf(_T("-*-%s-*-*-normal-*-*-*-*-*-*-*-*-*"), 
 645         if ( wxTestFontSpec(fontSpec
) ) 
 649         //else: no such family, use default one instead 
 655         case wxITALIC
:     xstyle 
= _T("i"); break; 
 656         case wxSLANT
:      xstyle 
= _T("o"); break; 
 657         case wxNORMAL
:     xstyle 
= _T("r"); break; 
 658         default:           xstyle 
= _T("*"); break; 
 664         case wxBOLD
:       xweight 
= _T("bold"); break; 
 666         case wxNORMAL
:     xweight 
= _T("medium"); break; 
 667         default:           xweight 
= _T("*"); break; 
 670     wxString xregistry
, xencoding
; 
 671     if ( encoding 
== wxFONTENCODING_DEFAULT 
) 
 673         // use the apps default 
 674         encoding 
= wxFont::GetDefaultEncoding(); 
 677     bool test 
= TRUE
;   // should we test for availability of encoding? 
 680         case wxFONTENCODING_ISO8859_1
: 
 681         case wxFONTENCODING_ISO8859_2
: 
 682         case wxFONTENCODING_ISO8859_3
: 
 683         case wxFONTENCODING_ISO8859_4
: 
 684         case wxFONTENCODING_ISO8859_5
: 
 685         case wxFONTENCODING_ISO8859_6
: 
 686         case wxFONTENCODING_ISO8859_7
: 
 687         case wxFONTENCODING_ISO8859_8
: 
 688         case wxFONTENCODING_ISO8859_9
: 
 689         case wxFONTENCODING_ISO8859_10
: 
 690         case wxFONTENCODING_ISO8859_11
: 
 691         case wxFONTENCODING_ISO8859_13
: 
 692         case wxFONTENCODING_ISO8859_14
: 
 693         case wxFONTENCODING_ISO8859_15
: 
 695                 int cp 
= encoding 
- wxFONTENCODING_ISO8859_1 
+ 1; 
 696                 xregistry 
= _T("iso8859"); 
 697                 xencoding
.Printf(_T("%d"), cp
); 
 701         case wxFONTENCODING_KOI8
: 
 702             xregistry 
= _T("koi8"); 
 703             if ( wxTestFontSpec(_T("-*-*-*-*-*-*-*-*-*-*-*-*-koi8-1")) ) 
 707                 // test passed, no need to do it once more 
 716         case wxFONTENCODING_CP1250
: 
 717         case wxFONTENCODING_CP1251
: 
 718         case wxFONTENCODING_CP1252
: 
 720                 int cp 
= encoding 
- wxFONTENCODING_CP1250 
+ 1250; 
 721                 fontSpec
.Printf(_T("-*-*-*-*-*-*-*-*-*-*-*-*-microsoft-cp%d"), 
 723                 if ( wxTestFontSpec(fontSpec
) ) 
 725                     xregistry 
= _T("microsoft"); 
 726                     xencoding
.Printf(_T("cp%d"), cp
); 
 728                     // test passed, no need to do it once more 
 733                     // fall back to LatinX 
 734                     xregistry 
= _T("iso8859"); 
 735                     xencoding
.Printf(_T("%d"), cp 
- 1249); 
 740         case wxFONTENCODING_SYSTEM
: 
 749         fontSpec
.Printf(_T("-*-*-*-*-*-*-*-*-*-*-*-*-%s-%s"), 
 750                         xregistry
.c_str(), xencoding
.c_str()); 
 751         if ( !wxTestFontSpec(fontSpec
) ) 
 753             // this encoding isn't available - what to do? 
 759     // construct the X font spec from our data 
 760     fontSpec
.Printf(_T("-*-%s-%s-%s-normal-*-*-%d-*-*-*-*-%s-%s"), 
 761                     xfamily
.c_str(), xweight
.c_str(), xstyle
.c_str(), 
 762                     pointSize
, xregistry
.c_str(), xencoding
.c_str()); 
 764     return wxLoadFont(fontSpec
); 
 767 wxNativeFont 
wxLoadQueryNearestFont(int pointSize
, 
 772                                     const wxString 
&facename
, 
 773                                     wxFontEncoding encoding
) 
 775     wxNativeFont font 
= wxLoadQueryFont( pointSize
, family
, style
, weight
, 
 776                                          underlined
, facename
, encoding 
); 
 780         // search up and down by stepsize 10 
 781         int max_size 
= pointSize 
+ 20 * (1 + (pointSize
/180)); 
 782         int min_size 
= pointSize 
- 20 * (1 + (pointSize
/180)); 
 786         // Search for smaller size (approx.) 
 787         for ( i 
= pointSize 
- 10; !font 
&& i 
>= 10 && i 
>= min_size
; i 
-= 10 ) 
 789             font 
= wxLoadQueryFont(i
, family
, style
, weight
, underlined
, 
 790                                    facename
, encoding 
); 
 793         // Search for larger size (approx.) 
 794         for ( i 
= pointSize 
+ 10; !font 
&& i 
<= max_size
; i 
+= 10 ) 
 796             font 
= wxLoadQueryFont( i
, family
, style
, weight
, underlined
, 
 797                                     facename
, encoding 
); 
 800         // Try default family 
 801         if ( !font 
&& family 
!= wxDEFAULT 
) 
 803             font 
= wxLoadQueryFont( pointSize
, wxDEFAULT
, style
, weight
, 
 804                                     underlined
, facename
, encoding 
); 
 810             font 
= wxLoadQueryFont(120, wxDEFAULT
, wxNORMAL
, wxNORMAL
, 
 811                                    underlined
, facename
, encoding 
);