1 /*
2 * misc.c: Miscellaneous functions
3 *
4 * Written by: Ullrich Hafner
5 *
6 * Copyright (C) 1998 Ullrich Hafner <hafner@bigfoot.de>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
21 */
22
23 /*
24 * $Date: 2000/09/25 18:15:23 $
25 * $Author: hafner $
26 * $Revision: 1.28 $
27 * $State: Exp $
28 */
29
30 #include "config.h"
31
32 #if HAVE_STDLIB_H
33 # include <stdlib.h>
34 #endif /* not HAVE_STDLIB_H */
35 #if HAVE_STRING_H
36 # include <string.h>
37 #else /* not HAVE_STRING_H */
38 # include <strings.h>
39 #endif /* not HAVE_STRING_H */
40 #if HAVE_SYS_TYPES_H
41 # include <sys/types.h>
42 #endif /* HAVE_SYS_TYPES_H */
43 #ifdef HAVE_UNISTD_H
44 # include <unistd.h>
45 #endif /* HAVE_UNISTD_H */
46 #include <stdio.h>
47 #include <errno.h>
48 #include <gtk/gtk.h>
49 #include <pwd.h>
50 #if HAVE_SYS_STAT_H
51 # include <sys/stat.h>
52 #endif /* HAVE_SYS_STAT_H */
53 /* unistd.h defines _POSIX_VERSION on POSIX.1 systems. */
54 #if defined(HAVE_DIRENT_H) || defined(_POSIX_VERSION)
55 # include <dirent.h>
56 # define NLENGTH(dirent) (strlen ((dirent)->d_name))
57 #else
58 # define dirent direct
59 # define NLENGTH(dirent) ((dirent)->d_namlen)
60 # ifdef HAVE_SYS_NDIR_H
61 # include <sys/ndir.h>
62 # endif /* HAVE_SYS_NDIR_H */
63 # ifdef HAVE_SYS_DIR_H
64 # include <sys/dir.h>
65 # endif /* HAVE_SYS_DIR_H */
66 # ifdef HAVE_NDIR_H
67 # include <ndir.h>
68 # endif /* HAVE_NDIR_H */
69 #endif /* not (HAVE_DIRENT_H or _POSIX_VERSION) */
70
71 #include "misc.h"
72 #include "load.h"
73 #include "dialog.h"
74 #include "error.h"
75
76 void
Free(void * ptr)77 Free (void *ptr)
78 {
79 g_free (ptr);
80 }
81
82 void *
Calloc(size_t n,size_t size)83 Calloc (size_t n, size_t size)
84 /*
85 * Allocate memory like calloc ().
86 *
87 * Return value: Pointer to the new block of memory on success,
88 * else terminate the program.
89 */
90 {
91 void *ptr; /* pointer to the new memory block */
92
93 if (n <= 0 || size <= 0)
94 error ("Can't allocate memory for %d items of size %d",
95 (unsigned) n, (unsigned) size);
96
97 ptr = g_malloc (n * size);
98 if (ptr == NULL)
99 error (_("Out of memory!"));
100 memset (ptr, 0, n * size);
101 return ptr;
102 }
103
104 char *
get_tempdir(void)105 get_tempdir (void)
106 {
107 static char * tempdir;
108 tempdir = getenv ("TMPDIR");
109 if (tempdir && *tempdir)
110 return g_strdup (tempdir);
111 else
112 return g_strdup ("/tmp");
113 }
114
115 char *
make_temporary_directory(void)116 make_temporary_directory (void)
117 {
118 #ifdef HAVE_MKDTEMP
119 static char *name = NULL;
120 static char *tmpdir;
121
122 Free (name);
123 tmpdir = get_tempdir ();
124 name = g_strconcat (tmpdir, "/wmdirXXXXXX", NULL);
125 Free (tmpdir);
126
127 if (!mkdtemp (name))
128 {
129 Free (name);
130 name = NULL;
131 }
132
133 #else /* not HAVE_MKDTEMP */
134 char *name = tmpnam (NULL);
135 if (name)
136 make_directory (name);
137
138 #endif /* not HAVE_MKDTEMP */
139
140 if (name)
141 return name;
142 else
143 {
144 make_directory ("/tmp/wmakerconf.dir");
145 return "/tmp/wmakerconf.dir";
146 }
147 }
148
149 char *
get_temporary_file_name(void)150 get_temporary_file_name (void)
151 {
152 #ifdef HAVE_MKSTEMP
153 static char *name = NULL;
154 static char *tmpdir;
155 int fd;
156
157 Free (name);
158 tmpdir = get_tempdir ();
159 name = g_strconcat (tmpdir, "/wmcnfXXXXXX", NULL);
160 Free (tmpdir);
161
162 if ((fd = mkstemp (name)) >= 0)
163 close (fd);
164 else
165 {
166 Free (name);
167 name = NULL;
168 }
169
170 #else /* not HAVE_MKSTEMP */
171 char *name = tmpnam (NULL);
172 #endif /* not HAVE_MKSTEMP */
173
174 if (name)
175 return name;
176 else
177 return "/tmp/wmakerconf.tmp";
178 }
179
180 char *
get_gnustep_path(const char * domain)181 get_gnustep_path (const char *domain)
182 /*
183 * Generate path to file 'domain' in users GNUstep directory
184 *
185 * E.g. domain = 'Defaults/WindowMaker', 'Defaults/WMRootMenu'
186 *
187 * Return value:
188 * pointer to char array containing generated path
189 */
190 {
191 const char *gspath = getenv ("GNUSTEP_USER_ROOT");
192
193 if (gspath)
194 return g_strconcat (gspath, "/", domain, NULL);
195 else
196 return g_strconcat (g_get_home_dir (), "/GNUstep/", domain, NULL);
197 }
198
199 char *
expand_tilde(const char * name)200 expand_tilde (const char *name)
201 /*
202 * Try to expand tilde (~) in filename.
203 *
204 * Return value:
205 * string with expanded path
206 */
207 {
208 struct passwd *user = NULL;
209
210 assert (name);
211
212 if (name [0] != '~' && name [0] != '$')
213 return g_strdup (name); /* nothing to do */
214
215 if (name [1] == '/' || !name [1] /* users home directory */
216 || strncmp (name, "$HOME", 5) == 0
217 || strncmp (name, "$(HOME)", 7) == 0)
218 {
219 if (name [0] == '~')
220 name += 1; /* skip ~ */
221 else if (strncmp (name, "$HOME", 5) == 0)
222 name += 5;
223 else if (strncmp (name, "$(HOME)", 7) == 0)
224 name += 7;
225
226 return g_strconcat (g_get_home_dir (), name, NULL);
227 }
228 else if (name [0] == '$') /* environment expansion */
229 {
230 const char *first = name + 1;
231 const char *last;
232 const char *rest;
233
234 if (*first == '(') /* $(ENV) */
235 {
236 if (!(last = strrchr (name, ')')))
237 return g_strdup (name); /* parse error */
238 first++;
239 rest = last + 1;
240 last--;
241 }
242 else
243 {
244 if (!(rest = strchr (name, '/'))) /* "$ENV" */
245 {
246 last = first + strlen (first) - 1;
247 rest = last + 1; /* empty */
248 }
249 else /* "$ENV/rest" */
250 last = rest - 1;
251 }
252 {
253 char *var = g_strndup (first, last - first + 1);
254 const char *dir = getenv (var);
255
256 Free (var);
257 if (dir)
258 return g_strconcat (dir, rest, NULL);
259 else
260 return g_strdup (name); /* parse error */
261 }
262 }
263 #ifdef HAVE_GETPWNAM
264 else /* other user directory */
265 {
266 char *usrname = strchr (name, '/');
267
268 if (usrname)
269 {
270 char *tmp = g_strndup (name + 1, usrname - name - 1);
271
272 user = getpwnam (tmp);
273 Free (tmp);
274 name = usrname; /* first slash */
275 }
276 else
277 {
278 user = getpwnam (name + 1);
279 name += strlen (name); /* empty string */
280 }
281 }
282
283 if (!user)
284 warning (_("Can't find passwd entry to expand\n`~' in filename %s"));
285 else
286 return g_strconcat (user->pw_dir, name, NULL);
287 #endif /* HAVE_GETPWNAM */
288
289 return g_strdup (name); /* no success */
290 }
291
292 bool_t
delete_file_or_dir(const char * filename)293 delete_file_or_dir (const char *filename)
294 /*
295 * Delete the given file or directory 'filename' (works like rm and rmdir).
296 * If the operation fails, show a popup error window.
297 *
298 * Return value:
299 * FALSE on success, TRUE on error
300 */
301 {
302 #ifdef HAVE_REMOVE
303
304 if (remove (filename) == -1)
305 {
306 dialog_popup (DIALOG_ERROR, NULL, NULL,
307 _("Can't delete\n'%s'\n\n%s"),
308 filename, strerror (errno));
309 return YES;
310 }
311 else
312 return NO;
313
314 #else /* not HAVE_REMOVE */
315
316 char *tmp;
317 DIR *dir = opendir (filename);
318 char *quotedname = protect_quotes (g_strdup (filename));
319 char *msg = g_strdup_printf (_("Can't delete\n`%s'"), filename);
320 bool_t returncode;
321
322 if (!dir) /* a file */
323 tmp = g_strconcat ("rm -f \"", quotedname, "\"", NULL);
324 else /* a directory */
325 {
326 tmp = g_strconcat ("rmdir \"", quotedname, "\"", NULL);
327 closedir (dir);
328 }
329
330 returncode = shell_command (tmp, msg);
331
332 g_free (tmp);
333 g_free (msg);
334 g_free (quotedname);
335
336 return returncode;
337
338 #endif /* not HAVE_REMOVE */
339 }
340
341 bool_t
rename_file_or_dir(const char * oldname,const char * newname)342 rename_file_or_dir (const char *oldname, const char *newname)
343 /*
344 * Rename file 'oldname' to 'newname' (works like mv).
345 * If the operation fails, show a popup error window.
346 *
347 * Return value:
348 * FALSE on success, TRUE on error
349 */
350 {
351 #ifdef HAVE_RENAME
352
353 if (rename (oldname, newname) == -1)
354 {
355 dialog_popup (DIALOG_ERROR, NULL, NULL,
356 _("Can't move\n'%s'\nto\n'%s'\n\n%s"),
357 oldname, newname, strerror (errno));
358 return YES;
359 }
360 else
361 return NO;
362
363 #else /* not HAVE_RENAME */
364
365 char *quotedoldname = protect_quotes (g_strdup (oldname));
366 char *quotednewname = protect_quotes (g_strdup (newname));
367 char *cmd = g_strconcat ("mv \"", quotedoldname, "\" \"",
368 quotednewname, "\"", NULL);
369 char *msg = g_strdup_printf (_("Can't move\n'%s'\nto\n'%s'"),
370 oldname, newname);
371 bool_t returncode;
372
373 returncode = shell_command (cmd, msg);
374
375 g_free (cmd);
376 g_free (msg);
377 g_free (quotednewname);
378 g_free (quotedoldname);
379
380 return returncode;
381
382 #endif /* not HAVE_RENAME */
383 }
384
385 bool_t
remove_directory(const char * directory)386 remove_directory (const char *directory)
387 /*
388 * Recursively delete the given directory 'directory' with all its
389 * files and subdirectories (works like rm -rf).
390 * If the operation fails, show a popup error window.
391 *
392 * Return value:
393 * FALSE on success, TRUE on error
394 */
395 {
396 DIR *dir = opendir (directory);
397
398 if (!dir) /* a file */
399 return delete_file_or_dir (directory);
400 else
401 {
402 struct dirent *file;
403
404 while ((file = readdir (dir)))
405 {
406 if (!streq (file->d_name, ".")
407 && !streq (file->d_name, ".."))
408 {
409 char *name = g_strconcat (directory, "/", file->d_name, NULL);
410 if (remove_directory (name))
411 {
412 closedir (dir);
413 Free (name);
414 return YES;
415 };
416 Free (name);
417 }
418 }
419 closedir (dir);
420 return delete_file_or_dir (directory);
421 }
422 }
423
424 bool_t
make_directory(const char * dirname)425 make_directory (const char *dirname)
426 /*
427 * Create a nmew directory 'dirname' (works like mkdir).
428 * If the operation fails, show a popup error window.
429 *
430 * Return value:
431 * FALSE on success, TRUE on error
432 */
433 {
434 #if defined(HAVE_MKDIR) && defined(HAVE_SYS_STAT_H)
435
436 if (mkdir (dirname, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH ) == -1)
437 {
438 dialog_popup (DIALOG_ERROR, NULL, NULL,
439 _("Can't create directory\n'%s'\n\n%s"),
440 dirname, strerror (errno));
441 return YES;
442 }
443 else
444 return NO;
445
446
447 #else /* not defined(HAVE_MKDIR) && defined(HAVE_SYS_STAT_H) */
448
449 char *quotedname = protect_quotes (g_strdup (dirname));
450 char *cmd = g_strconcat ("mkdir \"", quotedname, "\"", NULL);
451 char *msg = g_strdup_printf (_("Can't create directory\n`%s'\n"),
452 quotedname);
453
454 returncode = shell_command (cmd, msg);
455
456 g_free (cmd);
457 g_free (msg);
458 g_free (quotedname);
459
460 return returncode;
461
462 #endif /* not defined(HAVE_MKDIR) && defined(HAVE_SYS_STAT_H) */
463 }
464
465 bool_t
copy_file(const char * dst,const char * src)466 copy_file (const char *dst, const char *src)
467 /*
468 * Copy file 'src' to file or directory 'dst' (works like cp).
469 * If the operation fails, show a popup error window.
470 *
471 * Return value:
472 * FALSE on success, TRUE on error
473 */
474 {
475 if (!streq (src, dst))
476 {
477 DIR *dir = opendir (dst);
478 char *dst_name;
479 FILE *fsrc;
480 FILE *fdst;
481
482 if (dir) /* directory is destination */
483 {
484 closedir (dir);
485 if (streq (dst, g_path_get_dirname (src)))
486 return 0;
487 dst_name = g_strconcat (dst, "/", g_path_get_basename (src), NULL);
488 }
489 else
490 dst_name = g_strdup (dst);
491
492 fsrc = fopen (src, "r");
493 if (!fsrc)
494 {
495 dialog_popup (DIALOG_ERROR, NULL, NULL,
496 _("Can't open input file\n'%s'\n\n%s"),
497 src, strerror (errno));
498 return YES;
499 }
500 fdst = fopen (dst_name, "w");
501 if (!fdst)
502 {
503 fclose (fsrc);
504 dialog_popup (DIALOG_ERROR, NULL, NULL,
505 _("Can't open output file\n'%s'\n\n%s"),
506 dst_name, strerror (errno));
507 return YES;
508 }
509 {
510 char buffer [4096];
511 size_t n;
512
513 do
514 {
515 size_t m;
516
517 n = fread (buffer, 1, 4096, fsrc);
518 if (n)
519 m = fwrite (buffer, 1, n, fdst);
520 else
521 m = 0;
522 if (n != m)
523 {
524 fclose (fsrc);
525 fclose (fdst);
526 dialog_popup (DIALOG_ERROR, NULL, NULL,
527 _("Can't write to output file\n'%s'\n\n%s"),
528 dst_name, strerror (errno));
529 return YES;
530 }
531 } while (n == 4096);
532 }
533 fclose (fsrc);
534 fclose (fdst);
535 Free (dst_name);
536 }
537 return NO;
538 }
539
540 bool_t
shell_command(const char * command,const char * text)541 shell_command (const char *command, const char *text)
542 /*
543 * Execute shell 'command'.
544 * If the operation fails, show a popup error window.
545 *
546 * Return value:
547 * FALSE on success, TRUE on error
548 */
549 {
550 #if defined(HAVE_POPEN)
551 extern GtkWidget *log_text;
552 GtkTextBuffer *buffer;
553 GtkTextIter iter;
554 char *cmd = g_strconcat (command, " 2>&1", NULL);
555 FILE *pipe = popen (cmd, "r");
556 char tmp [MAXSTRLEN];
557
558 Free (cmd);
559 if (!pipe)
560 {
561 if (text)
562 dialog_popup (DIALOG_ERROR, NULL, NULL,
563 _("%s\nShell command failed.\n'%s'"), text, command);
564 else
565 dialog_popup (DIALOG_ERROR, NULL, NULL,
566 _("Shell command failed.\n'%s'"), command);
567 return YES;
568 }
569
570 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (log_text));
571 while (fgets (tmp, MAXSTRLEN, pipe))
572 {
573 gtk_text_buffer_get_iter_at_offset (buffer, &iter, -1);
574 gtk_text_buffer_insert (buffer, &iter, tmp, -1);
575
576 gtk_widget_show_all (gtk_widget_get_toplevel (log_text));
577 while (gtk_events_pending())
578 gtk_main_iteration();
579 }
580 if (pclose (pipe))
581 {
582 if (text)
583 dialog_popup (DIALOG_ERROR, NULL, NULL,
584 _("%s\nShell command failed.\n'%s'"), text, command);
585 else
586 dialog_popup (DIALOG_ERROR, NULL, NULL,
587 _("Shell command failed.\n'%s'"), command);
588 return YES;
589 }
590 else
591 return NO;
592
593 #else /* not HAVE_POPEN */
594
595 if (system (command))
596 {
597 if (text)
598 dialog_popup (DIALOG_ERROR, NULL, NULL,
599 _("%s\nShell command failed.\n'%s'\n"
600 "Please check `stderr' for more details."),
601 text, command);
602 else
603 dialog_popup (DIALOG_ERROR, NULL, NULL,
604 _("Shell command failed.\n'%s'\n"
605 "Please check `stderr' for more details."), command);
606 return YES;
607 }
608 else
609 return NO;
610
611 #endif /* not HAVE_POPEN */
612 }
613
614 bool_t
file_exists(const char * filename)615 file_exists (const char *filename)
616 /*
617 * Checks whether a directory or file 'filename' already exists.
618 *
619 * Return value:
620 * FALSE if file does not exist, TRUE if file exists
621 */
622 {
623 DIR *dir = opendir (filename);
624
625 if (dir) /* directory exists */
626 {
627 closedir (dir);
628 return YES;
629 }
630 else
631 {
632 FILE *file = fopen (filename, "r");
633 if (!file)
634 return NO;
635 else
636 {
637 fclose (file);
638 return YES;
639 }
640 }
641 }
642
643 char *
preview_name(const char * name)644 preview_name (const char *name)
645 /*
646 * Compute the filename of the preview of the given image 'name'.
647 * E.g., filename /path/to/foo.jpg is expanded to
648 * ~/.wmakerconf-path-to-foo.jpg
649 *
650 * Return value:
651 * preview filename
652 */
653 {
654 char *str = g_strdup (name);
655 char *ptr, *path;
656
657 for (ptr = str; *ptr; ptr++)
658 if (*ptr == '/')
659 *ptr = '-';
660 path = g_strconcat (g_get_home_dir (), "/.wmakerconf/", str, NULL);
661 Free (str);
662
663 return path;
664 }
665
666 proplist_t
read_proplist(const char * filename)667 read_proplist (const char *filename)
668 /*
669 * Call Alfredo's PropList parser ...
670 */
671 {
672 DIR *dir = opendir (filename);
673
674 if (dir) /* directory */
675 {
676 closedir (dir);
677 return NULL;
678 }
679 else
680 return ReadProplistFromFile (filename);
681 }
682
683 char *
protect_quotes(char * string)684 protect_quotes (char *string)
685 /*
686 * Protect double quotes in the given string.
687 * The old string is freed if it contains a double quote ".
688 *
689 * Return value:
690 * new string with \" instead of "
691 */
692 {
693 char *pos;
694 int offset = 0;
695
696 while ((pos = strchr (string + offset, '"')))
697 {
698 char *new;
699 if (pos > string + offset) /* not first character */
700 {
701 if (*(pos - 1) == '\\') /* if '\' is already present */
702 {
703 offset = pos - string + 1;
704 continue;
705 }
706 }
707 offset = pos - string + 2;
708
709 *pos = 0;
710 new = g_strconcat (string, "\\\"", pos + 1, NULL);
711 Free (string);
712
713 string = new;
714 }
715
716 return string;
717 }
718