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