]> git.saurik.com Git - wxWidgets.git/blob - src/unix/utilsunx.cpp
another attempt to improve combobox behaviour
[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
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 long wxExecute( const wxString& command, bool sync, wxProcess *process )
136 {
137 static const char *IFS = " \t\n";
138
139 wxCHECK_MSG( !command.IsEmpty(), 0, "can't exec empty command" );
140
141 int argc = 0;
142 char *argv[127];
143 char *tmp = new char[command.Len() + 1];
144 strcpy(tmp, command);
145
146 argv[argc++] = strtok(tmp, IFS);
147 while ((argv[argc++] = strtok((char *) NULL, IFS)) != NULL)
148 /* loop */ ;
149
150 long lRc = wxExecute(argv, sync, process);
151
152 delete [] tmp;
153
154 return lRc;
155 }
156
157 bool wxShell(const wxString& command)
158 {
159 wxString cmd;
160 if ( !!command )
161 cmd.Printf("xterm -e %s", command.c_str());
162 else
163 cmd = command;
164
165 return wxExecute(cmd) != 0;
166 }
167
168 void wxHandleProcessTermination(wxEndProcessData *proc_data)
169 {
170 int pid = (proc_data->pid > 0) ? proc_data->pid : -(proc_data->pid);
171
172 int status = 0;
173 wxWait4(pid, &status, 0, (rusage *) NULL);
174
175 if (proc_data->process)
176 proc_data->process->OnTerminate(proc_data->pid, status);
177
178 if (proc_data->pid > 0)
179 {
180 delete proc_data;
181 }
182 else
183 {
184 // wxExecute() will know about it
185 proc_data->exitcode = status;
186
187 proc_data->pid = 0;
188 }
189 }
190
191 long wxExecute( char **argv, bool sync, wxProcess *process )
192 {
193 wxCHECK_MSG( *argv, 0, "can't exec empty command" );
194
195 int end_proc_detect[2];
196
197 // create pipes
198 if (pipe(end_proc_detect) == -1)
199 {
200 wxLogSysError( _("Pipe creation failed") );
201 return 0;
202 }
203
204 // fork the process
205 #ifdef HAVE_VFORK
206 pid_t pid = vfork();
207 #else
208 pid_t pid = fork();
209 #endif
210 if (pid == -1)
211 {
212 wxLogSysError( _("Fork failed") );
213 return 0;
214 }
215 else if (pid == 0)
216 {
217 // we're in child
218 close(end_proc_detect[0]); // close reading side
219
220 // These three lines close the open file descriptors to to avoid any
221 // input/output which might block the process or irritate the user. If
222 // one wants proper IO for the subprocess, the "right thing to do is
223 // to start an xterm executing it.
224 if (sync == 0)
225 {
226 // leave stderr opened, it won't do any hurm
227 for ( int fd = 0; fd < FD_SETSIZE; fd++ )
228 {
229 if ( fd != end_proc_detect[1] && fd != STDERR_FILENO )
230 close(fd);
231 }
232 }
233
234 #if 0
235 close(STDERR_FILENO);
236
237 // some programs complain about stderr not being open, so redirect
238 // them:
239 open("/dev/null", O_RDONLY); // stdin
240 open("/dev/null", O_WRONLY); // stdout
241 open("/dev/null", O_WRONLY); // stderr
242 #endif
243
244 #ifdef _AIX
245 execvp ((const char *)*argv, (const char **)argv);
246 #else
247 execvp (*argv, argv);
248 #endif
249
250 // there is no return after successful exec()
251 fprintf(stderr, _("Can't execute '%s'\n"), *argv);
252
253 _exit(-1);
254 }
255 else
256 {
257 // we're in parent
258 close(end_proc_detect[1]); // close writing side
259
260 wxEndProcessData *data = new wxEndProcessData;
261 data->tag = wxAddProcessCallback(data, end_proc_detect[0]);
262
263 if ( sync )
264 {
265 wxASSERT_MSG( !process, "wxProcess param ignored for sync exec" );
266 data->process = NULL;
267
268 // sync execution: indicate it by negating the pid
269 data->pid = -pid;
270
271 // it will be set to 0 from GTK_EndProcessDetector
272 while (data->pid != 0)
273 wxYield();
274
275 int exitcode = data->exitcode;
276
277 delete data;
278
279 return exitcode;
280 }
281 else
282 {
283 // async execution, nothing special to do - caller will be
284 // notified about the process terminationif process != NULL, data
285 // will be deleted in GTK_EndProcessDetector
286 data->process = process;
287 data->pid = pid;
288
289 return pid;
290 }
291 }
292 }
293
294 // ----------------------------------------------------------------------------
295 // file and directory functions
296 // ----------------------------------------------------------------------------
297
298 const char* wxGetHomeDir( wxString *home )
299 {
300 *home = wxGetUserHome( wxString() );
301 if ( home->IsEmpty() )
302 *home = "/";
303
304 return home->c_str();
305 }
306
307 char *wxGetUserHome( const wxString &user )
308 {
309 struct passwd *who = (struct passwd *) NULL;
310
311 if (user.IsNull() || (user== ""))
312 {
313 register char *ptr;
314
315 if ((ptr = getenv("HOME")) != NULL)
316 {
317 return ptr;
318 }
319 if ((ptr = getenv("USER")) != NULL || (ptr = getenv("LOGNAME")) != NULL)
320 {
321 who = getpwnam(ptr);
322 }
323
324 // We now make sure the the user exists!
325 if (who == NULL)
326 {
327 who = getpwuid(getuid());
328 }
329 }
330 else
331 {
332 who = getpwnam (user);
333 }
334
335 return who ? who->pw_dir : (char*)NULL;
336 }
337
338 // ----------------------------------------------------------------------------
339 // id routines
340 // ----------------------------------------------------------------------------
341
342 bool wxGetHostName(char *buf, int sz)
343 {
344 wxCHECK_MSG( buf, FALSE, "NULL pointer in wxGetHostName" );
345
346 *buf = '\0';
347
348 // we're using uname() which is POSIX instead of less standard sysinfo()
349 #if defined(HAVE_UNAME)
350 struct utsname uts;
351 bool ok = uname(&uts) != -1;
352 if ( ok )
353 {
354 strncpy(buf, uts.nodename, sz - 1);
355 buf[sz] = '\0';
356 }
357 #elif defined(HAVE_GETHOSTNAME)
358 bool ok = gethostname(buf, sz) != -1;
359 #else
360 wxFAIL_MSG("don't know host name for this machibe");
361
362 bool ok = FALSE;
363 #endif
364
365 if ( !ok )
366 {
367 wxLogSysError(_("Cannot get the hostname"));
368 }
369
370 return ok;
371 }
372
373 bool wxGetUserId(char *buf, int sz)
374 {
375 struct passwd *who;
376
377 *buf = '\0';
378 if ((who = getpwuid(getuid ())) != NULL)
379 {
380 strncpy (buf, who->pw_name, sz - 1);
381 return TRUE;
382 }
383
384 return FALSE;
385 }
386
387 bool wxGetUserName(char *buf, int sz)
388 {
389 struct passwd *who;
390 char *comma;
391
392 *buf = '\0';
393 if ((who = getpwuid (getuid ())) != NULL) {
394 comma = strchr(who->pw_gecos, ',');
395 if (comma)
396 *comma = '\0'; // cut off non-name comment fields
397 strncpy (buf, who->pw_gecos, sz - 1);
398 return TRUE;
399 }
400
401 return FALSE;
402 }
403
404 // ----------------------------------------------------------------------------
405 // error and debug output routines (deprecated, use wxLog)
406 // ----------------------------------------------------------------------------
407
408 void wxDebugMsg( const char *format, ... )
409 {
410 va_list ap;
411 va_start( ap, format );
412 vfprintf( stderr, format, ap );
413 fflush( stderr );
414 va_end(ap);
415 }
416
417 void wxError( const wxString &msg, const wxString &title )
418 {
419 fprintf( stderr, _("Error ") );
420 if (!title.IsNull()) fprintf( stderr, "%s ", WXSTRINGCAST(title) );
421 if (!msg.IsNull()) fprintf( stderr, ": %s", WXSTRINGCAST(msg) );
422 fprintf( stderr, ".\n" );
423 }
424
425 void wxFatalError( const wxString &msg, const wxString &title )
426 {
427 fprintf( stderr, _("Error ") );
428 if (!title.IsNull()) fprintf( stderr, "%s ", WXSTRINGCAST(title) );
429 if (!msg.IsNull()) fprintf( stderr, ": %s", WXSTRINGCAST(msg) );
430 fprintf( stderr, ".\n" );
431 exit(3); // the same exit code as for abort()
432 }
433
434 //------------------------------------------------------------------------
435 // directory routines
436 //------------------------------------------------------------------------
437
438 bool wxDirExists( const wxString& dir )
439 {
440 char buf[500];
441 strcpy( buf, WXSTRINGCAST(dir) );
442 struct stat sbuf;
443 return ((stat(buf, &sbuf) != -1) && S_ISDIR(sbuf.st_mode) ? TRUE : FALSE);
444 }