]> git.saurik.com Git - wxWidgets.git/blob - src/unix/utilsunx.cpp
Oops, I didn't see Robert had already corrected 16bit BMP typo
[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
24 #include "wx/utils.h"
25 #include "wx/process.h"
26
27 #include "wx/unix/execute.h"
28
29 #include <stdarg.h>
30 #include <dirent.h>
31 #include <string.h>
32 #include <sys/stat.h>
33 #include <sys/types.h>
34 #include <unistd.h>
35 #include <sys/wait.h>
36 #include <pwd.h>
37 #include <errno.h>
38 #include <netdb.h>
39 #include <signal.h>
40 #include <fcntl.h> // for O_WRONLY and friends
41 #include <time.h> // nanosleep() and/or usleep()
42 #include <ctype.h> // isspace()
43
44 // JACS: needed for FD_SETSIZE
45 #include <sys/time.h>
46
47 #if HAVE_UNAME
48 #include <sys/utsname.h> // for uname()
49 #endif // HAVE_UNAME
50
51 // ----------------------------------------------------------------------------
52 // conditional compilation
53 // ----------------------------------------------------------------------------
54
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__)
62 extern "C"
63 {
64 #ifdef __SUN__
65 int usleep(unsigned int usec);
66 #else // !Sun
67 void usleep(unsigned long usec);
68 #endif // Sun/!Sun
69 };
70 #endif // Unices without usleep()
71
72 // ============================================================================
73 // implementation
74 // ============================================================================
75
76 // ----------------------------------------------------------------------------
77 // sleeping
78 // ----------------------------------------------------------------------------
79
80 void wxSleep(int nSecs)
81 {
82 sleep(nSecs);
83 }
84
85 void wxUsleep(unsigned long milliseconds)
86 {
87 #if HAVE_NANOSLEEP
88 timespec tmReq;
89 tmReq.tv_sec = milliseconds / 1000;
90 tmReq.tv_nsec = (milliseconds % 1000) * 1000 * 1000;
91
92 // we're not interested in remaining time nor in return value
93 (void)nanosleep(&tmReq, (timespec *)NULL);
94 #elif HAVE_USLEEP
95 // uncomment this if you feel brave or if you are sure that your version
96 // of Solaris has a safe usleep() function but please notice that usleep()
97 // is known to lead to crashes in MT programs in Solaris 2.[67] and is not
98 // documented as MT-Safe
99 #if defined(__SUN__) && wxUSE_THREADS
100 #error "usleep() cannot be used in MT programs under Solaris."
101 #endif // Sun
102
103 usleep(milliseconds * 1000); // usleep(3) wants microseconds
104 #else // !sleep function
105 #error "usleep() or nanosleep() function required for wxUsleep"
106 #endif // sleep function
107 }
108
109 // ----------------------------------------------------------------------------
110 // process management
111 // ----------------------------------------------------------------------------
112
113 int wxKill(long pid, wxSignal sig)
114 {
115 return kill(pid, (int)sig);
116 }
117
118 #define WXEXECUTE_NARGS 127
119
120 long wxExecute( const wxString& command, bool sync, wxProcess *process )
121 {
122 wxCHECK_MSG( !command.IsEmpty(), 0, _T("can't exec empty command") );
123
124 int argc = 0;
125 wxChar *argv[WXEXECUTE_NARGS];
126 wxString argument;
127 const wxChar *cptr = command.c_str();
128 wxChar quotechar = _T('\0'); // is arg quoted?
129 bool escaped = FALSE;
130
131 // split the command line in arguments
132 do
133 {
134 argument=_T("");
135 quotechar = _T('\0');
136
137 // eat leading whitespace:
138 while ( wxIsspace(*cptr) )
139 cptr++;
140
141 if ( *cptr == _T('\'') || *cptr == _T('"') )
142 quotechar = *cptr++;
143
144 do
145 {
146 if ( *cptr == _T('\\') && ! escaped )
147 {
148 escaped = TRUE;
149 cptr++;
150 continue;
151 }
152
153 // all other characters:
154 argument += *cptr++;
155 escaped = FALSE;
156
157 // have we reached the end of the argument?
158 if ( (*cptr == quotechar && ! escaped)
159 || (quotechar == _T('\0') && wxIsspace(*cptr))
160 || *cptr == _T('\0') )
161 {
162 wxASSERT_MSG( argc < WXEXECUTE_NARGS,
163 _T("too many arguments in wxExecute") );
164
165 argv[argc] = new wxChar[argument.length() + 1];
166 wxStrcpy(argv[argc], argument.c_str());
167 argc++;
168
169 // if not at end of buffer, swallow last character:
170 if(*cptr)
171 cptr++;
172
173 break; // done with this one, start over
174 }
175 } while(*cptr);
176 } while(*cptr);
177 argv[argc] = NULL;
178
179 // do execute the command
180 long lRc = wxExecute(argv, sync, process);
181
182 // clean up
183 argc = 0;
184 while( argv[argc] )
185 delete [] argv[argc++];
186
187 return lRc;
188 }
189
190 bool wxShell(const wxString& command)
191 {
192 wxString cmd;
193 if ( !!command )
194 cmd.Printf(_T("xterm -e %s"), command.c_str());
195 else
196 cmd = command;
197
198 return wxExecute(cmd) != 0;
199 }
200
201 void wxHandleProcessTermination(wxEndProcessData *proc_data)
202 {
203 int pid = (proc_data->pid > 0) ? proc_data->pid : -(proc_data->pid);
204
205 // waitpid is POSIX so should be available everywhere, however on older
206 // systems wait() might be used instead in a loop (until the right pid
207 // terminates)
208 int status = 0;
209 if ( waitpid(pid, &status, 0) == -1 || !WIFEXITED(status) )
210 {
211 wxLogSysError(_("Waiting for subprocess termination failed"));
212 }
213 else
214 {
215 // notify user about termination if required
216 if (proc_data->process)
217 {
218 proc_data->process->OnTerminate(proc_data->pid,
219 WEXITSTATUS(status));
220 }
221 }
222
223 // clean up
224 if ( proc_data->pid > 0 )
225 {
226 delete proc_data;
227 }
228 else
229 {
230 // wxExecute() will know about it
231 proc_data->exitcode = status;
232
233 proc_data->pid = 0;
234 }
235 }
236
237 long wxExecute( wxChar **argv, bool sync, wxProcess *process )
238 {
239 wxCHECK_MSG( *argv, 0, _T("can't exec empty command") );
240
241 int end_proc_detect[2];
242 #if wxUSE_UNICODE
243 int mb_argc = 0;
244 char *mb_argv[WXEXECUTE_NARGS];
245
246 while (argv[mb_argc]) {
247 wxWX2MBbuf mb_arg = wxConv_libc.cWX2MB(argv[mb_argc]);
248 mb_argv[mb_argc] = strdup(mb_arg);
249 mb_argc++;
250 }
251 mb_argv[mb_argc] = (char *) NULL;
252 #else
253 wxChar **mb_argv = argv;
254 #endif
255
256 // create pipes
257 if (pipe(end_proc_detect) == -1)
258 {
259 wxLogSysError( _("Pipe creation failed") );
260 #if wxUSE_UNICODE
261 mb_argc = 0;
262 while (mb_argv[mb_argc])
263 free(mb_argv[mb_argc++]);
264 #endif
265 return 0;
266 }
267
268 // fork the process
269 #ifdef HAVE_VFORK
270 pid_t pid = vfork();
271 #else
272 pid_t pid = fork();
273 #endif
274 if (pid == -1)
275 {
276 wxLogSysError( _("Fork failed") );
277 #if wxUSE_UNICODE
278 mb_argc = 0;
279 while (mb_argv[mb_argc])
280 free(mb_argv[mb_argc++]);
281 #endif
282 return 0;
283 }
284 else if (pid == 0)
285 {
286 // we're in child
287 close(end_proc_detect[0]); // close reading side
288
289 // These three lines close the open file descriptors to to avoid any
290 // input/output which might block the process or irritate the user. If
291 // one wants proper IO for the subprocess, the right thing to do is
292 // to start an xterm executing it.
293 if (sync == 0)
294 {
295 // leave stderr opened, it won't do any hurm
296 for ( int fd = 0; fd < FD_SETSIZE; fd++ )
297 {
298 if ( fd != end_proc_detect[1] && fd != STDERR_FILENO )
299 close(fd);
300 }
301 }
302
303 #if 0
304 close(STDERR_FILENO);
305
306 // some programs complain about stderr not being open, so redirect
307 // them:
308 open("/dev/null", O_RDONLY); // stdin
309 open("/dev/null", O_WRONLY); // stdout
310 open("/dev/null", O_WRONLY); // stderr
311 #endif
312
313 execvp (*mb_argv, mb_argv);
314
315 // there is no return after successful exec()
316 wxFprintf(stderr, _("Can't execute '%s'\n"), *argv);
317
318 _exit(-1);
319 }
320 else
321 {
322 // we're in parent
323 close(end_proc_detect[1]); // close writing side
324
325 wxEndProcessData *data = new wxEndProcessData;
326 data->tag = wxAddProcessCallback(data, end_proc_detect[0]);
327
328 #if wxUSE_UNICODE
329 mb_argc = 0;
330 while (mb_argv[mb_argc])
331 free(mb_argv[mb_argc++]);
332 #endif
333
334 if ( sync )
335 {
336 wxASSERT_MSG( !process, _T("wxProcess param ignored for sync exec") );
337 data->process = NULL;
338
339 // sync execution: indicate it by negating the pid
340 data->pid = -pid;
341
342 // it will be set to 0 from GTK_EndProcessDetector
343 while (data->pid != 0)
344 wxYield();
345
346 int exitcode = data->exitcode;
347
348 delete data;
349
350 return exitcode;
351 }
352 else
353 {
354 // async execution, nothing special to do - caller will be
355 // notified about the process terminationif process != NULL, data
356 // will be deleted in GTK_EndProcessDetector
357 data->process = process;
358 data->pid = pid;
359
360 return pid;
361 }
362 }
363 }
364
365 // ----------------------------------------------------------------------------
366 // file and directory functions
367 // ----------------------------------------------------------------------------
368
369 const wxChar* wxGetHomeDir( wxString *home )
370 {
371 *home = wxGetUserHome( wxString() );
372 if ( home->IsEmpty() )
373 *home = _T("/");
374
375 return home->c_str();
376 }
377
378 #if wxUSE_UNICODE
379 const wxMB2WXbuf wxGetUserHome( const wxString &user )
380 #else // just for binary compatibility
381 char *wxGetUserHome( const wxString &user )
382 #endif
383 {
384 struct passwd *who = (struct passwd *) NULL;
385
386 if ( !user )
387 {
388 register wxChar *ptr;
389
390 if ((ptr = wxGetenv(_T("HOME"))) != NULL)
391 {
392 return ptr;
393 }
394 if ((ptr = wxGetenv(_T("USER"))) != NULL || (ptr = wxGetenv(_T("LOGNAME"))) != NULL)
395 {
396 who = getpwnam(wxConv_libc.cWX2MB(ptr));
397 }
398
399 // We now make sure the the user exists!
400 if (who == NULL)
401 {
402 who = getpwuid(getuid());
403 }
404 }
405 else
406 {
407 who = getpwnam (user.mb_str());
408 }
409
410 #if wxUSE_UNICODE
411 return who ? wxConv_libc.cMB2WX(who->pw_dir) : (wxMB2WXbuf)((wxChar*)NULL);
412 #else
413 return who ? who->pw_dir : ((char*)NULL);
414 #endif
415 }
416
417 // ----------------------------------------------------------------------------
418 // network and user id routines
419 // ----------------------------------------------------------------------------
420
421 // retrieve either the hostname or FQDN depending on platform (caller must
422 // check whether it's one or the other, this is why this function is for
423 // private use only)
424 static bool wxGetHostNameInternal(wxChar *buf, int sz)
425 {
426 wxCHECK_MSG( buf, FALSE, _T("NULL pointer in wxGetHostNameInternal") );
427
428 *buf = _T('\0');
429
430 // we're using uname() which is POSIX instead of less standard sysinfo()
431 #if defined(HAVE_UNAME)
432 struct utsname uts;
433 bool ok = uname(&uts) != -1;
434 if ( ok )
435 {
436 wxStrncpy(buf, wxConv_libc.cMB2WX(uts.nodename), sz - 1);
437 buf[sz] = _T('\0');
438 }
439 #elif defined(HAVE_GETHOSTNAME)
440 bool ok = gethostname(buf, sz) != -1;
441 #else // no uname, no gethostname
442 wxFAIL_MSG(_T("don't know host name for this machine"));
443
444 bool ok = FALSE;
445 #endif // uname/gethostname
446
447 if ( !ok )
448 {
449 wxLogSysError(_("Cannot get the hostname"));
450 }
451
452 return ok;
453 }
454
455 bool wxGetHostName(wxChar *buf, int sz)
456 {
457 bool ok = wxGetHostNameInternal(buf, sz);
458
459 if ( ok )
460 {
461 // BSD systems return the FQDN, we only want the hostname, so extract
462 // it (we consider that dots are domain separators)
463 wxChar *dot = wxStrchr(buf, _T('.'));
464 if ( dot )
465 {
466 // nuke it
467 *dot = _T('\0');
468 }
469 }
470
471 return ok;
472 }
473
474 bool wxGetFullHostName(wxChar *buf, int sz)
475 {
476 bool ok = wxGetHostNameInternal(buf, sz);
477
478 if ( ok )
479 {
480 if ( !wxStrchr(buf, _T('.')) )
481 {
482 struct hostent *host = gethostbyname(wxConv_libc.cWX2MB(buf));
483 if ( !host )
484 {
485 wxLogSysError(_("Cannot get the official hostname"));
486
487 ok = FALSE;
488 }
489 else
490 {
491 // the canonical name
492 wxStrncpy(buf, wxConv_libc.cMB2WX(host->h_name), sz);
493 }
494 }
495 //else: it's already a FQDN (BSD behaves this way)
496 }
497
498 return ok;
499 }
500
501 bool wxGetUserId(wxChar *buf, int sz)
502 {
503 struct passwd *who;
504
505 *buf = _T('\0');
506 if ((who = getpwuid(getuid ())) != NULL)
507 {
508 wxStrncpy (buf, wxConv_libc.cMB2WX(who->pw_name), sz - 1);
509 return TRUE;
510 }
511
512 return FALSE;
513 }
514
515 bool wxGetUserName(wxChar *buf, int sz)
516 {
517 struct passwd *who;
518 char *comma;
519
520 *buf = _T('\0');
521 if ((who = getpwuid (getuid ())) != NULL) {
522 comma = strchr(who->pw_gecos, ',');
523 if (comma)
524 *comma = '\0'; // cut off non-name comment fields
525 wxStrncpy (buf, wxConv_libc.cMB2WX(who->pw_gecos), sz - 1);
526 return TRUE;
527 }
528
529 return FALSE;
530 }
531
532 // ----------------------------------------------------------------------------
533 // error and debug output routines (deprecated, use wxLog)
534 // ----------------------------------------------------------------------------
535
536 void wxDebugMsg( const char *format, ... )
537 {
538 va_list ap;
539 va_start( ap, format );
540 vfprintf( stderr, format, ap );
541 fflush( stderr );
542 va_end(ap);
543 }
544
545 void wxError( const wxString &msg, const wxString &title )
546 {
547 wxFprintf( stderr, _("Error ") );
548 if (!title.IsNull()) wxFprintf( stderr, _T("%s "), WXSTRINGCAST(title) );
549 if (!msg.IsNull()) wxFprintf( stderr, _T(": %s"), WXSTRINGCAST(msg) );
550 wxFprintf( stderr, _T(".\n") );
551 }
552
553 void wxFatalError( const wxString &msg, const wxString &title )
554 {
555 wxFprintf( stderr, _("Error ") );
556 if (!title.IsNull()) wxFprintf( stderr, _T("%s "), WXSTRINGCAST(title) );
557 if (!msg.IsNull()) wxFprintf( stderr, _T(": %s"), WXSTRINGCAST(msg) );
558 wxFprintf( stderr, _T(".\n") );
559 exit(3); // the same exit code as for abort()
560 }