]> git.saurik.com Git - wxWidgets.git/blob - src/unix/utilsunx.cpp
Motif cell highlighting problem fixed
[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 #ifdef HAVE_UNAME
44 #include <sys/utsname.h> // for uname()
45 #endif // HAVE_UNAME
46
47 // ----------------------------------------------------------------------------
48 // conditional compilation
49 // ----------------------------------------------------------------------------
50
51 // many versions of Unices have this function, but it is not defined in system
52 // headers - please add your system here if it is the case for your OS.
53 // SunOS < 5.6 (i.e. Solaris < 2.6) and DG-UX are like this.
54 #if !defined(HAVE_USLEEP) && \
55 (defined(__SUN__) && !defined(__SunOs_5_6) && \
56 !defined(__SunOs_5_7) && !defined(__SUNPRO_CC)) || \
57 defined(__osf__)
58 extern "C"
59 {
60 #ifdef __SUN__
61 int usleep(unsigned int usec);
62 #else // !Sun
63 void usleep(unsigned long usec);
64 #endif // Sun/!Sun
65 };
66 #endif // Unices without usleep()
67
68 // many versions of Unices have this function, but it is not defined in system
69 // headers - please add your system here if it is the case for your OS.
70 // SunOS (and Solaris) and DG-UX are like this.
71 #if defined(__SOLARIS__) || defined(__osf__)
72 extern "C"
73 {
74 pid_t wait4(pid_t pid, int *statusp, int options,
75 struct rusage *rusage);
76 }
77
78 #define wxWait4(pid, stat, flags, rusage) wait4(pid, stat, flags, rusage)
79 #elif defined(__sgi) || defined(__HPUX__)
80 // no wait4() at all on these systems
81 // TODO verify whether wait3() really works in this situation
82 #define wxWait4(pid, stat, flags, rusage) wait3(stat, flags, rusage)
83 #else
84 // other Unices: assume have wait4(), although it's not standard (but
85 // Linux and FreeBSD do have it)
86 #define wxWait4(pid, stat, flags, rusage) wait4(pid, stat, flags, rusage)
87 #endif // wait4()
88
89 // ============================================================================
90 // implementation
91 // ============================================================================
92
93 // ----------------------------------------------------------------------------
94 // sleeping
95 // ----------------------------------------------------------------------------
96
97 void wxSleep(int nSecs)
98 {
99 sleep(nSecs);
100 }
101
102 void wxUsleep(unsigned long milliseconds)
103 {
104 #if defined(HAVE_NANOSLEEP)
105 timespec tmReq;
106 tmReq.tv_sec = milliseconds / 1000;
107 tmReq.tv_nsec = (milliseconds % 1000) * 1000 * 1000;
108
109 // we're not interested in remaining time nor in return value
110 (void)nanosleep(&tmReq, (timespec *)NULL);
111 #elif defined(HAVE_USLEEP)
112 // uncomment this if you feel brave or if you are sure that your version
113 // of Solaris has a safe usleep() function but please notice that usleep()
114 // is known to lead to crashes in MT programs in Solaris 2.[67] and is not
115 // documented as MT-Safe
116 #if defined(__SUN__) && defined(wxUSE_THREADS)
117 #error "usleep() cannot be used in MT programs under Solaris."
118 #endif // Sun
119
120 usleep(milliseconds * 1000); // usleep(3) wants microseconds
121 #else // !sleep function
122 #error "usleep() or nanosleep() function required for wxUsleep"
123 #endif // sleep function
124 }
125
126 // ----------------------------------------------------------------------------
127 // process management
128 // ----------------------------------------------------------------------------
129
130 int wxKill(long pid, int sig)
131 {
132 return kill(pid, sig);
133 }
134
135 #define WXEXECUTE_NARGS 127
136
137 long wxExecute( const wxString& command, bool sync, wxProcess *process )
138 {
139 wxCHECK_MSG( !command.IsEmpty(), 0, "can't exec empty command" );
140
141 int argc = 0;
142 char *argv[WXEXECUTE_NARGS];
143 wxString argument;
144 const char *cptr = command.c_str();
145 char quotechar = '\0'; // is arg quoted?
146 bool escaped = FALSE;
147
148 do
149 {
150 argument="";
151 quotechar = '\0';
152 // eat leading whitespace:
153 while(*cptr && isspace(*cptr))
154 cptr++;
155 if(*cptr == '\'' || *cptr == '"')
156 quotechar = *cptr++;
157 do
158 {
159 if(*cptr == '\\' && ! escaped)
160 {
161 escaped = TRUE;
162 cptr++;
163 continue;
164 }
165 // all other characters:
166 argument += *cptr ++;
167 escaped = FALSE;
168 // Have we reached the end of the argument?
169 if((*cptr == quotechar && ! escaped)
170 || (quotechar == '\0' && isspace(*cptr))
171 || *cptr == '\0')
172 {
173 wxASSERT(argc < WXEXECUTE_NARGS);
174 argv[argc] = new char[argument.Len()+1];
175 strcpy(argv[argc], argument.c_str());
176 argc++;
177 // if not at end of buffer, swallow last character:
178 if(*cptr) cptr++;
179 break; // done with this one, start over
180 }
181 }while(*cptr);
182 }while(*cptr);
183 argv[argc] = NULL;
184
185 long lRc = wxExecute(argv, sync, process);
186
187 argc = 0;
188 while(argv[argc])
189 delete [] argv[argc++];
190
191 return lRc;
192 }
193
194 bool wxShell(const wxString& command)
195 {
196 wxString cmd;
197 if ( !!command )
198 cmd.Printf("xterm -e %s", command.c_str());
199 else
200 cmd = command;
201
202 return wxExecute(cmd) != 0;
203 }
204
205 void wxHandleProcessTermination(wxEndProcessData *proc_data)
206 {
207 int pid = (proc_data->pid > 0) ? proc_data->pid : -(proc_data->pid);
208
209 int status = 0;
210 wxWait4(pid, &status, 0, (rusage *) NULL);
211
212 if (proc_data->process)
213 proc_data->process->OnTerminate(proc_data->pid, status);
214
215 if (proc_data->pid > 0)
216 {
217 delete proc_data;
218 }
219 else
220 {
221 // wxExecute() will know about it
222 proc_data->exitcode = status;
223
224 proc_data->pid = 0;
225 }
226 }
227
228 long wxExecute( char **argv, bool sync, wxProcess *process )
229 {
230 wxCHECK_MSG( *argv, 0, "can't exec empty command" );
231
232 int end_proc_detect[2];
233
234 // create pipes
235 if (pipe(end_proc_detect) == -1)
236 {
237 wxLogSysError( _("Pipe creation failed") );
238 return 0;
239 }
240
241 // fork the process
242 #ifdef HAVE_VFORK
243 pid_t pid = vfork();
244 #else
245 pid_t pid = fork();
246 #endif
247 if (pid == -1)
248 {
249 wxLogSysError( _("Fork failed") );
250 return 0;
251 }
252 else if (pid == 0)
253 {
254 // we're in child
255 close(end_proc_detect[0]); // close reading side
256
257 // These three lines close the open file descriptors to to avoid any
258 // input/output which might block the process or irritate the user. If
259 // one wants proper IO for the subprocess, the "right thing to do is
260 // to start an xterm executing it.
261 if (sync == 0)
262 {
263 // leave stderr opened, it won't do any hurm
264 for ( int fd = 0; fd < FD_SETSIZE; fd++ )
265 {
266 if ( fd != end_proc_detect[1] && fd != STDERR_FILENO )
267 close(fd);
268 }
269 }
270
271 #if 0
272 close(STDERR_FILENO);
273
274 // some programs complain about stderr not being open, so redirect
275 // them:
276 open("/dev/null", O_RDONLY); // stdin
277 open("/dev/null", O_WRONLY); // stdout
278 open("/dev/null", O_WRONLY); // stderr
279 #endif
280
281 #ifdef _AIX
282 execvp ((const char *)*argv, (const char **)argv);
283 #else
284 execvp (*argv, argv);
285 #endif
286
287 // there is no return after successful exec()
288 fprintf(stderr, _("Can't execute '%s'\n"), *argv);
289
290 _exit(-1);
291 }
292 else
293 {
294 // we're in parent
295 close(end_proc_detect[1]); // close writing side
296
297 wxEndProcessData *data = new wxEndProcessData;
298 data->tag = wxAddProcessCallback(data, end_proc_detect[0]);
299
300 if ( sync )
301 {
302 wxASSERT_MSG( !process, "wxProcess param ignored for sync exec" );
303 data->process = NULL;
304
305 // sync execution: indicate it by negating the pid
306 data->pid = -pid;
307
308 // it will be set to 0 from GTK_EndProcessDetector
309 while (data->pid != 0)
310 wxYield();
311
312 int exitcode = data->exitcode;
313
314 delete data;
315
316 return exitcode;
317 }
318 else
319 {
320 // async execution, nothing special to do - caller will be
321 // notified about the process terminationif process != NULL, data
322 // will be deleted in GTK_EndProcessDetector
323 data->process = process;
324 data->pid = pid;
325
326 return pid;
327 }
328 }
329 }
330
331 // ----------------------------------------------------------------------------
332 // file and directory functions
333 // ----------------------------------------------------------------------------
334
335 const char* wxGetHomeDir( wxString *home )
336 {
337 *home = wxGetUserHome( wxString() );
338 if ( home->IsEmpty() )
339 *home = "/";
340
341 return home->c_str();
342 }
343
344 char *wxGetUserHome( const wxString &user )
345 {
346 struct passwd *who = (struct passwd *) NULL;
347
348 if (user.IsNull() || (user== ""))
349 {
350 register char *ptr;
351
352 if ((ptr = getenv("HOME")) != NULL)
353 {
354 return ptr;
355 }
356 if ((ptr = getenv("USER")) != NULL || (ptr = getenv("LOGNAME")) != NULL)
357 {
358 who = getpwnam(ptr);
359 }
360
361 // We now make sure the the user exists!
362 if (who == NULL)
363 {
364 who = getpwuid(getuid());
365 }
366 }
367 else
368 {
369 who = getpwnam (user);
370 }
371
372 return who ? who->pw_dir : (char*)NULL;
373 }
374
375 // ----------------------------------------------------------------------------
376 // id routines
377 // ----------------------------------------------------------------------------
378
379 bool wxGetHostName(char *buf, int sz)
380 {
381 wxCHECK_MSG( buf, FALSE, "NULL pointer in wxGetHostName" );
382
383 *buf = '\0';
384
385 // we're using uname() which is POSIX instead of less standard sysinfo()
386 #if defined(HAVE_UNAME)
387 struct utsname uts;
388 bool ok = uname(&uts) != -1;
389 if ( ok )
390 {
391 strncpy(buf, uts.nodename, sz - 1);
392 buf[sz] = '\0';
393 }
394 #elif defined(HAVE_GETHOSTNAME)
395 bool ok = gethostname(buf, sz) != -1;
396 #else
397 wxFAIL_MSG("don't know host name for this machibe");
398
399 bool ok = FALSE;
400 #endif
401
402 if ( !ok )
403 {
404 wxLogSysError(_("Cannot get the hostname"));
405 }
406
407 return ok;
408 }
409
410 bool wxGetUserId(char *buf, int sz)
411 {
412 struct passwd *who;
413
414 *buf = '\0';
415 if ((who = getpwuid(getuid ())) != NULL)
416 {
417 strncpy (buf, who->pw_name, sz - 1);
418 return TRUE;
419 }
420
421 return FALSE;
422 }
423
424 bool wxGetUserName(char *buf, int sz)
425 {
426 struct passwd *who;
427 char *comma;
428
429 *buf = '\0';
430 if ((who = getpwuid (getuid ())) != NULL) {
431 comma = strchr(who->pw_gecos, ',');
432 if (comma)
433 *comma = '\0'; // cut off non-name comment fields
434 strncpy (buf, who->pw_gecos, sz - 1);
435 return TRUE;
436 }
437
438 return FALSE;
439 }
440
441 // ----------------------------------------------------------------------------
442 // error and debug output routines (deprecated, use wxLog)
443 // ----------------------------------------------------------------------------
444
445 void wxDebugMsg( const char *format, ... )
446 {
447 va_list ap;
448 va_start( ap, format );
449 vfprintf( stderr, format, ap );
450 fflush( stderr );
451 va_end(ap);
452 }
453
454 void wxError( const wxString &msg, const wxString &title )
455 {
456 fprintf( stderr, _("Error ") );
457 if (!title.IsNull()) fprintf( stderr, "%s ", WXSTRINGCAST(title) );
458 if (!msg.IsNull()) fprintf( stderr, ": %s", WXSTRINGCAST(msg) );
459 fprintf( stderr, ".\n" );
460 }
461
462 void wxFatalError( const wxString &msg, const wxString &title )
463 {
464 fprintf( stderr, _("Error ") );
465 if (!title.IsNull()) fprintf( stderr, "%s ", WXSTRINGCAST(title) );
466 if (!msg.IsNull()) fprintf( stderr, ": %s", WXSTRINGCAST(msg) );
467 fprintf( stderr, ".\n" );
468 exit(3); // the same exit code as for abort()
469 }
470
471 //------------------------------------------------------------------------
472 // directory routines
473 //------------------------------------------------------------------------
474
475 bool wxDirExists( const wxString& dir )
476 {
477 char buf[500];
478 strcpy( buf, WXSTRINGCAST(dir) );
479 struct stat sbuf;
480 return ((stat(buf, &sbuf) != -1) && S_ISDIR(sbuf.st_mode) ? TRUE : FALSE);
481 }