]> git.saurik.com Git - wxWidgets.git/blame - src/unix/utilsunx.cpp
wxProgressDialog now accepts wxGA_SMOOTH style
[wxWidgets.git] / src / unix / utilsunx.cpp
CommitLineData
518b5d2f
VZ
1/////////////////////////////////////////////////////////////////////////////
2// Name: utilsunx.cpp
3// Purpose: generic Unix implementation of many wx functions
4// Author: Vadim Zeitlin
5// Id: $Id$
6// Copyright: (c) 1998 Robert Roebling, Vadim Zeitlin
7// Licence: wxWindows licence
8/////////////////////////////////////////////////////////////////////////////
9
10// ============================================================================
11// declarations
12// ============================================================================
13
14// ----------------------------------------------------------------------------
15// headers
16// ----------------------------------------------------------------------------
17
18#include "wx/defs.h"
19#include "wx/string.h"
20
21#include "wx/intl.h"
22#include "wx/log.h"
23
24#include "wx/utils.h"
25#include "wx/process.h"
bdc72a22 26#include "wx/thread.h"
518b5d2f
VZ
27
28#include "wx/unix/execute.h"
29
30#include <stdarg.h>
31#include <dirent.h>
32#include <string.h>
33#include <sys/stat.h>
34#include <sys/types.h>
35#include <unistd.h>
36#include <sys/wait.h>
37#include <pwd.h>
38#include <errno.h>
39#include <netdb.h>
40#include <signal.h>
41#include <fcntl.h> // for O_WRONLY and friends
42#include <time.h> // nanosleep() and/or usleep()
fad866f4 43#include <ctype.h> // isspace()
b12915c1 44#include <sys/time.h> // needed for FD_SETSIZE
7bcb11d3 45
0fcdf6dc 46#ifdef HAVE_UNAME
518b5d2f
VZ
47 #include <sys/utsname.h> // for uname()
48#endif // HAVE_UNAME
49
50// ----------------------------------------------------------------------------
51// conditional compilation
52// ----------------------------------------------------------------------------
53
54// many versions of Unices have this function, but it is not defined in system
55// headers - please add your system here if it is the case for your OS.
56// SunOS < 5.6 (i.e. Solaris < 2.6) and DG-UX are like this.
1363811b
VZ
57#if !defined(HAVE_USLEEP) && \
58 (defined(__SUN__) && !defined(__SunOs_5_6) && \
518b5d2f 59 !defined(__SunOs_5_7) && !defined(__SUNPRO_CC)) || \
fd9811b1 60 defined(__osf__) || defined(__EMX__)
518b5d2f
VZ
61 extern "C"
62 {
1363811b
VZ
63 #ifdef __SUN__
64 int usleep(unsigned int usec);
65 #else // !Sun
bdc72a22
VZ
66 #ifdef __EMX__
67 /* I copied this from the XFree86 diffs. AV. */
68 #define INCL_DOSPROCESS
69 #include <os2.h>
70 inline void usleep(unsigned long delay)
71 {
72 DosSleep(delay ? (delay/1000l) : 1l);
73 }
74 #else // !Sun && !EMX
75 void usleep(unsigned long usec);
76 #endif
e6daf794 77 #endif // Sun/EMX/Something else
518b5d2f 78 };
bdc72a22
VZ
79
80 #define HAVE_USLEEP 1
518b5d2f
VZ
81#endif // Unices without usleep()
82
518b5d2f
VZ
83// ============================================================================
84// implementation
85// ============================================================================
86
87// ----------------------------------------------------------------------------
88// sleeping
89// ----------------------------------------------------------------------------
90
91void wxSleep(int nSecs)
92{
93 sleep(nSecs);
94}
95
96void wxUsleep(unsigned long milliseconds)
97{
b12915c1 98#if defined(HAVE_NANOSLEEP)
518b5d2f 99 timespec tmReq;
13111b2a 100 tmReq.tv_sec = (time_t)(milliseconds / 1000);
518b5d2f
VZ
101 tmReq.tv_nsec = (milliseconds % 1000) * 1000 * 1000;
102
103 // we're not interested in remaining time nor in return value
104 (void)nanosleep(&tmReq, (timespec *)NULL);
b12915c1 105#elif defined(HAVE_USLEEP)
518b5d2f
VZ
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
ea18eed9 110 #if defined(__SUN__) && wxUSE_THREADS
518b5d2f
VZ
111 #error "usleep() cannot be used in MT programs under Solaris."
112 #endif // Sun
113
114 usleep(milliseconds * 1000); // usleep(3) wants microseconds
b12915c1
VZ
115#elif defined(HAVE_SLEEP)
116 // under BeOS sleep() takes seconds (what about other platforms, if any?)
117 sleep(milliseconds * 1000);
518b5d2f
VZ
118#else // !sleep function
119 #error "usleep() or nanosleep() function required for wxUsleep"
120#endif // sleep function
121}
122
123// ----------------------------------------------------------------------------
124// process management
125// ----------------------------------------------------------------------------
126
0fb67cd1 127int wxKill(long pid, wxSignal sig)
518b5d2f 128{
13111b2a 129 return kill((pid_t)pid, (int)sig);
518b5d2f
VZ
130}
131
fad866f4
KB
132#define WXEXECUTE_NARGS 127
133
518b5d2f
VZ
134long wxExecute( const wxString& command, bool sync, wxProcess *process )
135{
223d09f6 136 wxCHECK_MSG( !command.IsEmpty(), 0, wxT("can't exec empty command") );
518b5d2f
VZ
137
138 int argc = 0;
05079acc 139 wxChar *argv[WXEXECUTE_NARGS];
fad866f4 140 wxString argument;
05079acc 141 const wxChar *cptr = command.c_str();
223d09f6 142 wxChar quotechar = wxT('\0'); // is arg quoted?
fad866f4 143 bool escaped = FALSE;
518b5d2f 144
0ed9a934 145 // split the command line in arguments
fad866f4
KB
146 do
147 {
223d09f6
KB
148 argument=wxT("");
149 quotechar = wxT('\0');
0ed9a934 150
fad866f4 151 // eat leading whitespace:
05079acc 152 while ( wxIsspace(*cptr) )
fad866f4 153 cptr++;
0ed9a934 154
223d09f6 155 if ( *cptr == wxT('\'') || *cptr == wxT('"') )
fad866f4 156 quotechar = *cptr++;
0ed9a934 157
fad866f4
KB
158 do
159 {
223d09f6 160 if ( *cptr == wxT('\\') && ! escaped )
fad866f4
KB
161 {
162 escaped = TRUE;
163 cptr++;
164 continue;
165 }
0ed9a934 166
fad866f4 167 // all other characters:
0ed9a934 168 argument += *cptr++;
fad866f4 169 escaped = FALSE;
0ed9a934
VZ
170
171 // have we reached the end of the argument?
172 if ( (*cptr == quotechar && ! escaped)
223d09f6
KB
173 || (quotechar == wxT('\0') && wxIsspace(*cptr))
174 || *cptr == wxT('\0') )
fad866f4 175 {
0ed9a934 176 wxASSERT_MSG( argc < WXEXECUTE_NARGS,
223d09f6 177 wxT("too many arguments in wxExecute") );
0ed9a934 178
05079acc
OK
179 argv[argc] = new wxChar[argument.length() + 1];
180 wxStrcpy(argv[argc], argument.c_str());
fad866f4 181 argc++;
0ed9a934 182
fad866f4 183 // if not at end of buffer, swallow last character:
0ed9a934
VZ
184 if(*cptr)
185 cptr++;
186
fad866f4
KB
187 break; // done with this one, start over
188 }
0ed9a934
VZ
189 } while(*cptr);
190 } while(*cptr);
fad866f4 191 argv[argc] = NULL;
0ed9a934
VZ
192
193 // do execute the command
518b5d2f
VZ
194 long lRc = wxExecute(argv, sync, process);
195
0ed9a934 196 // clean up
fad866f4 197 argc = 0;
0ed9a934 198 while( argv[argc] )
fad866f4 199 delete [] argv[argc++];
518b5d2f
VZ
200
201 return lRc;
202}
203
204bool wxShell(const wxString& command)
205{
206 wxString cmd;
207 if ( !!command )
223d09f6 208 cmd.Printf(wxT("xterm -e %s"), command.c_str());
518b5d2f
VZ
209 else
210 cmd = command;
211
212 return wxExecute(cmd) != 0;
213}
214
215void wxHandleProcessTermination(wxEndProcessData *proc_data)
216{
217 int pid = (proc_data->pid > 0) ? proc_data->pid : -(proc_data->pid);
218
0ed9a934
VZ
219 // waitpid is POSIX so should be available everywhere, however on older
220 // systems wait() might be used instead in a loop (until the right pid
221 // terminates)
518b5d2f 222 int status = 0;
ab857a4e
KB
223 int rc;
224
bdc72a22 225 // wait for child termination and if waitpid() was interrupted, try again
ab857a4e 226 do
bdc72a22 227 {
ab857a4e 228 rc = waitpid(pid, &status, 0);
bdc72a22
VZ
229 }
230 while ( rc == -1 && errno == EINTR );
231
ab857a4e 232
ab857a4e 233 if( rc == -1 || ! (WIFEXITED(status) || WIFSIGNALED(status)) )
0ed9a934 234 {
ab857a4e
KB
235 wxLogSysError(_("Waiting for subprocess termination failed"));
236 /* AFAIK, this can only happen if something went wrong within
bdc72a22 237 wxGTK, i.e. due to a race condition or some serious bug.
ab857a4e
KB
238 After having fixed the order of statements in
239 GTK_EndProcessDetector(). (KB)
240 */
0ed9a934
VZ
241 }
242 else
243 {
244 // notify user about termination if required
245 if (proc_data->process)
246 {
247 proc_data->process->OnTerminate(proc_data->pid,
248 WEXITSTATUS(status));
249 }
ab857a4e
KB
250 // clean up
251 if ( proc_data->pid > 0 )
252 {
253 delete proc_data;
254 }
255 else
256 {
257 // wxExecute() will know about it
258 proc_data->exitcode = status;
bdc72a22 259
ab857a4e
KB
260 proc_data->pid = 0;
261 }
518b5d2f
VZ
262 }
263}
264
05079acc 265long wxExecute( wxChar **argv, bool sync, wxProcess *process )
518b5d2f 266{
223d09f6 267 wxCHECK_MSG( *argv, 0, wxT("can't exec empty command") );
518b5d2f 268
05079acc
OK
269#if wxUSE_UNICODE
270 int mb_argc = 0;
271 char *mb_argv[WXEXECUTE_NARGS];
272
e90c1d2a
VZ
273 while (argv[mb_argc])
274 {
275 wxWX2MBbuf mb_arg = wxConvertWX2MB(argv[mb_argc]);
05079acc
OK
276 mb_argv[mb_argc] = strdup(mb_arg);
277 mb_argc++;
278 }
279 mb_argv[mb_argc] = (char *) NULL;
e90c1d2a
VZ
280
281 // this macro will free memory we used above
282 #define ARGS_CLEANUP \
345b0247 283 for ( mb_argc = 0; mb_argv[mb_argc]; mb_argc++ ) \
e90c1d2a
VZ
284 free(mb_argv[mb_argc])
285#else // ANSI
286 // no need for cleanup
287 #define ARGS_CLEANUP
288
05079acc 289 wxChar **mb_argv = argv;
e90c1d2a 290#endif // Unicode/ANSI
518b5d2f 291
e90c1d2a 292#if wxUSE_GUI
518b5d2f 293 // create pipes
e90c1d2a 294 int end_proc_detect[2];
518b5d2f
VZ
295 if (pipe(end_proc_detect) == -1)
296 {
297 wxLogSysError( _("Pipe creation failed") );
e90c1d2a
VZ
298
299 ARGS_CLEANUP;
300
518b5d2f
VZ
301 return 0;
302 }
e90c1d2a 303#endif // wxUSE_GUI
518b5d2f
VZ
304
305 // fork the process
0fcdf6dc 306#ifdef HAVE_VFORK
518b5d2f
VZ
307 pid_t pid = vfork();
308#else
309 pid_t pid = fork();
310#endif
311 if (pid == -1)
312 {
313 wxLogSysError( _("Fork failed") );
e90c1d2a
VZ
314
315 ARGS_CLEANUP;
316
518b5d2f
VZ
317 return 0;
318 }
319 else if (pid == 0)
320 {
e90c1d2a 321#if wxUSE_GUI
518b5d2f
VZ
322 // we're in child
323 close(end_proc_detect[0]); // close reading side
e90c1d2a 324#endif // wxUSE_GUI
518b5d2f
VZ
325
326 // These three lines close the open file descriptors to to avoid any
327 // input/output which might block the process or irritate the user. If
d6086ea6 328 // one wants proper IO for the subprocess, the right thing to do is
518b5d2f
VZ
329 // to start an xterm executing it.
330 if (sync == 0)
331 {
332 // leave stderr opened, it won't do any hurm
333 for ( int fd = 0; fd < FD_SETSIZE; fd++ )
334 {
e90c1d2a
VZ
335#if wxUSE_GUI
336 if ( fd == end_proc_detect[1] )
337 continue;
338#endif // wxUSE_GUI
339
340 if ( fd != STDERR_FILENO )
518b5d2f
VZ
341 close(fd);
342 }
343 }
344
345#if 0
346 close(STDERR_FILENO);
347
348 // some programs complain about stderr not being open, so redirect
349 // them:
350 open("/dev/null", O_RDONLY); // stdin
351 open("/dev/null", O_WRONLY); // stdout
352 open("/dev/null", O_WRONLY); // stderr
353#endif
354
05079acc 355 execvp (*mb_argv, mb_argv);
518b5d2f
VZ
356
357 // there is no return after successful exec()
05079acc 358 wxFprintf(stderr, _("Can't execute '%s'\n"), *argv);
518b5d2f
VZ
359
360 _exit(-1);
361 }
362 else
363 {
e90c1d2a 364#if wxUSE_GUI
518b5d2f 365 wxEndProcessData *data = new wxEndProcessData;
ab857a4e 366
518b5d2f 367
e90c1d2a 368 ARGS_CLEANUP;
05079acc 369
518b5d2f
VZ
370 if ( sync )
371 {
223d09f6 372 wxASSERT_MSG( !process, wxT("wxProcess param ignored for sync exec") );
518b5d2f
VZ
373 data->process = NULL;
374
375 // sync execution: indicate it by negating the pid
376 data->pid = -pid;
ab857a4e
KB
377 data->tag = wxAddProcessCallback(data, end_proc_detect[0]);
378 // we're in parent
379 close(end_proc_detect[1]); // close writing side
518b5d2f
VZ
380
381 // it will be set to 0 from GTK_EndProcessDetector
382 while (data->pid != 0)
383 wxYield();
384
385 int exitcode = data->exitcode;
386
387 delete data;
388
389 return exitcode;
390 }
391 else
392 {
393 // async execution, nothing special to do - caller will be
ab857a4e 394 // notified about the process termination if process != NULL, data
518b5d2f
VZ
395 // will be deleted in GTK_EndProcessDetector
396 data->process = process;
397 data->pid = pid;
ab857a4e
KB
398 data->tag = wxAddProcessCallback(data, end_proc_detect[0]);
399 // we're in parent
400 close(end_proc_detect[1]); // close writing side
518b5d2f
VZ
401
402 return pid;
403 }
e90c1d2a 404#else // !wxUSE_GUI
223d09f6 405 wxASSERT_MSG( sync, wxT("async execution not supported yet") );
e90c1d2a
VZ
406
407 int exitcode = 0;
408 if ( waitpid(pid, &exitcode, 0) == -1 || !WIFEXITED(exitcode) )
409 {
410 wxLogSysError(_("Waiting for subprocess termination failed"));
411 }
412
413 return exitcode;
414#endif // wxUSE_GUI
518b5d2f 415 }
338dd992 416 return 0;
e90c1d2a
VZ
417
418 #undef ARGS_CLEANUP
518b5d2f
VZ
419}
420
421// ----------------------------------------------------------------------------
422// file and directory functions
423// ----------------------------------------------------------------------------
424
05079acc 425const wxChar* wxGetHomeDir( wxString *home )
518b5d2f
VZ
426{
427 *home = wxGetUserHome( wxString() );
428 if ( home->IsEmpty() )
223d09f6 429 *home = wxT("/");
518b5d2f
VZ
430
431 return home->c_str();
432}
433
05079acc
OK
434#if wxUSE_UNICODE
435const wxMB2WXbuf wxGetUserHome( const wxString &user )
e90c1d2a 436#else // just for binary compatibility -- there is no 'const' here
518b5d2f 437char *wxGetUserHome( const wxString &user )
05079acc 438#endif
518b5d2f
VZ
439{
440 struct passwd *who = (struct passwd *) NULL;
441
0fb67cd1 442 if ( !user )
518b5d2f 443 {
e90c1d2a 444 wxChar *ptr;
518b5d2f 445
223d09f6 446 if ((ptr = wxGetenv(wxT("HOME"))) != NULL)
518b5d2f
VZ
447 {
448 return ptr;
449 }
223d09f6 450 if ((ptr = wxGetenv(wxT("USER"))) != NULL || (ptr = wxGetenv(wxT("LOGNAME"))) != NULL)
518b5d2f 451 {
e90c1d2a 452 who = getpwnam(wxConvertWX2MB(ptr));
518b5d2f
VZ
453 }
454
455 // We now make sure the the user exists!
456 if (who == NULL)
457 {
458 who = getpwuid(getuid());
459 }
460 }
461 else
462 {
05079acc 463 who = getpwnam (user.mb_str());
518b5d2f
VZ
464 }
465
af111fc3 466 return wxConvertMB2WX(who ? who->pw_dir : 0);
518b5d2f
VZ
467}
468
469// ----------------------------------------------------------------------------
0fb67cd1 470// network and user id routines
518b5d2f
VZ
471// ----------------------------------------------------------------------------
472
0fb67cd1
VZ
473// retrieve either the hostname or FQDN depending on platform (caller must
474// check whether it's one or the other, this is why this function is for
475// private use only)
05079acc 476static bool wxGetHostNameInternal(wxChar *buf, int sz)
518b5d2f 477{
223d09f6 478 wxCHECK_MSG( buf, FALSE, wxT("NULL pointer in wxGetHostNameInternal") );
518b5d2f 479
223d09f6 480 *buf = wxT('\0');
518b5d2f
VZ
481
482 // we're using uname() which is POSIX instead of less standard sysinfo()
483#if defined(HAVE_UNAME)
cc743a6f 484 struct utsname uts;
518b5d2f
VZ
485 bool ok = uname(&uts) != -1;
486 if ( ok )
487 {
e90c1d2a 488 wxStrncpy(buf, wxConvertMB2WX(uts.nodename), sz - 1);
223d09f6 489 buf[sz] = wxT('\0');
518b5d2f
VZ
490 }
491#elif defined(HAVE_GETHOSTNAME)
492 bool ok = gethostname(buf, sz) != -1;
0fb67cd1 493#else // no uname, no gethostname
223d09f6 494 wxFAIL_MSG(wxT("don't know host name for this machine"));
518b5d2f
VZ
495
496 bool ok = FALSE;
0fb67cd1 497#endif // uname/gethostname
518b5d2f
VZ
498
499 if ( !ok )
500 {
501 wxLogSysError(_("Cannot get the hostname"));
502 }
503
504 return ok;
505}
506
05079acc 507bool wxGetHostName(wxChar *buf, int sz)
0fb67cd1
VZ
508{
509 bool ok = wxGetHostNameInternal(buf, sz);
510
511 if ( ok )
512 {
513 // BSD systems return the FQDN, we only want the hostname, so extract
514 // it (we consider that dots are domain separators)
223d09f6 515 wxChar *dot = wxStrchr(buf, wxT('.'));
0fb67cd1
VZ
516 if ( dot )
517 {
518 // nuke it
223d09f6 519 *dot = wxT('\0');
0fb67cd1
VZ
520 }
521 }
522
523 return ok;
524}
525
05079acc 526bool wxGetFullHostName(wxChar *buf, int sz)
0fb67cd1
VZ
527{
528 bool ok = wxGetHostNameInternal(buf, sz);
529
530 if ( ok )
531 {
223d09f6 532 if ( !wxStrchr(buf, wxT('.')) )
0fb67cd1 533 {
e90c1d2a 534 struct hostent *host = gethostbyname(wxConvertWX2MB(buf));
0fb67cd1
VZ
535 if ( !host )
536 {
537 wxLogSysError(_("Cannot get the official hostname"));
538
539 ok = FALSE;
540 }
541 else
542 {
543 // the canonical name
e90c1d2a 544 wxStrncpy(buf, wxConvertMB2WX(host->h_name), sz);
0fb67cd1
VZ
545 }
546 }
547 //else: it's already a FQDN (BSD behaves this way)
548 }
549
550 return ok;
551}
552
05079acc 553bool wxGetUserId(wxChar *buf, int sz)
518b5d2f
VZ
554{
555 struct passwd *who;
556
223d09f6 557 *buf = wxT('\0');
518b5d2f
VZ
558 if ((who = getpwuid(getuid ())) != NULL)
559 {
e90c1d2a 560 wxStrncpy (buf, wxConvertMB2WX(who->pw_name), sz - 1);
518b5d2f
VZ
561 return TRUE;
562 }
563
564 return FALSE;
565}
566
05079acc 567bool wxGetUserName(wxChar *buf, int sz)
518b5d2f
VZ
568{
569 struct passwd *who;
518b5d2f 570
223d09f6 571 *buf = wxT('\0');
b12915c1
VZ
572 if ((who = getpwuid (getuid ())) != NULL)
573 {
574 // pw_gecos field in struct passwd is not standard
575#if HAVE_PW_GECOS
576 char *comma = strchr(who->pw_gecos, ',');
518b5d2f
VZ
577 if (comma)
578 *comma = '\0'; // cut off non-name comment fields
e90c1d2a 579 wxStrncpy (buf, wxConvertMB2WX(who->pw_gecos), sz - 1);
b12915c1 580#else // !HAVE_PW_GECOS
0fcdf6dc 581 wxStrncpy (buf, wxConvertMB2WX(who->pw_name), sz - 1);
b12915c1 582#endif // HAVE_PW_GECOS/!HAVE_PW_GECOS
518b5d2f
VZ
583 return TRUE;
584 }
585
586 return FALSE;
587}
588
bdc72a22
VZ
589wxString wxGetOsDescription()
590{
591#ifndef WXWIN_OS_DESCRIPTION
592 #error WXWIN_OS_DESCRIPTION should be defined in config.h by configure
593#else
594 return WXWIN_OS_DESCRIPTION;
595#endif
596}
597
518b5d2f
VZ
598// ----------------------------------------------------------------------------
599// error and debug output routines (deprecated, use wxLog)
600// ----------------------------------------------------------------------------
601
602void wxDebugMsg( const char *format, ... )
603{
604 va_list ap;
605 va_start( ap, format );
606 vfprintf( stderr, format, ap );
607 fflush( stderr );
608 va_end(ap);
609}
610
611void wxError( const wxString &msg, const wxString &title )
612{
05079acc 613 wxFprintf( stderr, _("Error ") );
223d09f6
KB
614 if (!title.IsNull()) wxFprintf( stderr, wxT("%s "), WXSTRINGCAST(title) );
615 if (!msg.IsNull()) wxFprintf( stderr, wxT(": %s"), WXSTRINGCAST(msg) );
616 wxFprintf( stderr, wxT(".\n") );
518b5d2f
VZ
617}
618
619void wxFatalError( const wxString &msg, const wxString &title )
620{
05079acc 621 wxFprintf( stderr, _("Error ") );
223d09f6
KB
622 if (!title.IsNull()) wxFprintf( stderr, wxT("%s "), WXSTRINGCAST(title) );
623 if (!msg.IsNull()) wxFprintf( stderr, wxT(": %s"), WXSTRINGCAST(msg) );
624 wxFprintf( stderr, wxT(".\n") );
518b5d2f
VZ
625 exit(3); // the same exit code as for abort()
626}
93ccaed8 627