/* * misc.c: Miscellaneous functions * * Written by: Ullrich Hafner * * Copyright (C) 1998 Ullrich Hafner * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. */ /* * $Date: 2000/09/25 18:15:23 $ * $Author: hafner $ * $Revision: 1.28 $ * $State: Exp $ */ #include "config.h" #if HAVE_STDLIB_H # include #endif /* not HAVE_STDLIB_H */ #if HAVE_STRING_H # include #else /* not HAVE_STRING_H */ # include #endif /* not HAVE_STRING_H */ #if HAVE_SYS_TYPES_H # include #endif /* HAVE_SYS_TYPES_H */ #ifdef HAVE_UNISTD_H # include #endif /* HAVE_UNISTD_H */ #include #include #include #include #if HAVE_SYS_STAT_H # include #endif /* HAVE_SYS_STAT_H */ /* unistd.h defines _POSIX_VERSION on POSIX.1 systems. */ #if defined(HAVE_DIRENT_H) || defined(_POSIX_VERSION) # include # define NLENGTH(dirent) (strlen ((dirent)->d_name)) #else # define dirent direct # define NLENGTH(dirent) ((dirent)->d_namlen) # ifdef HAVE_SYS_NDIR_H # include # endif /* HAVE_SYS_NDIR_H */ # ifdef HAVE_SYS_DIR_H # include # endif /* HAVE_SYS_DIR_H */ # ifdef HAVE_NDIR_H # include # endif /* HAVE_NDIR_H */ #endif /* not (HAVE_DIRENT_H or _POSIX_VERSION) */ #include "misc.h" #include "load.h" #include "dialog.h" #include "error.h" void Free (void *ptr) { g_free (ptr); } void * Calloc (size_t n, size_t size) /* * Allocate memory like calloc (). * * Return value: Pointer to the new block of memory on success, * else terminate the program. */ { void *ptr; /* pointer to the new memory block */ if (n <= 0 || size <= 0) error ("Can't allocate memory for %d items of size %d", (unsigned) n, (unsigned) size); ptr = g_malloc (n * size); if (ptr == NULL) error (_("Out of memory!")); memset (ptr, 0, n * size); return ptr; } char * get_tempdir (void) { static char * tempdir; tempdir = getenv ("TMPDIR"); if (tempdir && *tempdir) return g_strdup (tempdir); else return g_strdup ("/tmp"); } char * make_temporary_directory (void) { #ifdef HAVE_MKDTEMP static char *name = NULL; static char *tmpdir; Free (name); tmpdir = get_tempdir (); name = g_strconcat (tmpdir, "/wmdirXXXXXX", NULL); Free (tmpdir); if (!mkdtemp (name)) { Free (name); name = NULL; } #else /* not HAVE_MKDTEMP */ char *name = tmpnam (NULL); if (name) make_directory (name); #endif /* not HAVE_MKDTEMP */ if (name) return name; else { make_directory ("/tmp/wmakerconf.dir"); return "/tmp/wmakerconf.dir"; } } char * get_temporary_file_name (void) { #ifdef HAVE_MKSTEMP static char *name = NULL; static char *tmpdir; int fd; Free (name); tmpdir = get_tempdir (); name = g_strconcat (tmpdir, "/wmcnfXXXXXX", NULL); Free (tmpdir); if ((fd = mkstemp (name)) >= 0) close (fd); else { Free (name); name = NULL; } #else /* not HAVE_MKSTEMP */ char *name = tmpnam (NULL); #endif /* not HAVE_MKSTEMP */ if (name) return name; else return "/tmp/wmakerconf.tmp"; } char * get_gnustep_path (const char *domain) /* * Generate path to file 'domain' in users GNUstep directory * * E.g. domain = 'Defaults/WindowMaker', 'Defaults/WMRootMenu' * * Return value: * pointer to char array containing generated path */ { const char *gspath = getenv ("GNUSTEP_USER_ROOT"); if (gspath) return g_strconcat (gspath, "/", domain, NULL); else return g_strconcat (g_get_home_dir (), "/GNUstep/", domain, NULL); } char * expand_tilde (const char *name) /* * Try to expand tilde (~) in filename. * * Return value: * string with expanded path */ { struct passwd *user = NULL; assert (name); if (name [0] != '~' && name [0] != '$') return g_strdup (name); /* nothing to do */ if (name [1] == '/' || !name [1] /* users home directory */ || strncmp (name, "$HOME", 5) == 0 || strncmp (name, "$(HOME)", 7) == 0) { if (name [0] == '~') name += 1; /* skip ~ */ else if (strncmp (name, "$HOME", 5) == 0) name += 5; else if (strncmp (name, "$(HOME)", 7) == 0) name += 7; return g_strconcat (g_get_home_dir (), name, NULL); } else if (name [0] == '$') /* environment expansion */ { const char *first = name + 1; const char *last; const char *rest; if (*first == '(') /* $(ENV) */ { if (!(last = strrchr (name, ')'))) return g_strdup (name); /* parse error */ first++; rest = last + 1; last--; } else { if (!(rest = strchr (name, '/'))) /* "$ENV" */ { last = first + strlen (first) - 1; rest = last + 1; /* empty */ } else /* "$ENV/rest" */ last = rest - 1; } { char *var = g_strndup (first, last - first + 1); const char *dir = getenv (var); Free (var); if (dir) return g_strconcat (dir, rest, NULL); else return g_strdup (name); /* parse error */ } } #ifdef HAVE_GETPWNAM else /* other user directory */ { char *usrname = strchr (name, '/'); if (usrname) { char *tmp = g_strndup (name + 1, usrname - name - 1); user = getpwnam (tmp); Free (tmp); name = usrname; /* first slash */ } else { user = getpwnam (name + 1); name += strlen (name); /* empty string */ } } if (!user) warning (_("Can't find passwd entry to expand\n`~' in filename %s")); else return g_strconcat (user->pw_dir, name, NULL); #endif /* HAVE_GETPWNAM */ return g_strdup (name); /* no success */ } bool_t delete_file_or_dir (const char *filename) /* * Delete the given file or directory 'filename' (works like rm and rmdir). * If the operation fails, show a popup error window. * * Return value: * FALSE on success, TRUE on error */ { #ifdef HAVE_REMOVE if (remove (filename) == -1) { dialog_popup (DIALOG_ERROR, NULL, NULL, _("Can't delete\n'%s'\n\n%s"), filename, strerror (errno)); return YES; } else return NO; #else /* not HAVE_REMOVE */ char *tmp; DIR *dir = opendir (filename); char *quotedname = protect_quotes (g_strdup (filename)); char *msg = g_strdup_printf (_("Can't delete\n`%s'"), filename); bool_t returncode; if (!dir) /* a file */ tmp = g_strconcat ("rm -f \"", quotedname, "\"", NULL); else /* a directory */ { tmp = g_strconcat ("rmdir \"", quotedname, "\"", NULL); closedir (dir); } returncode = shell_command (tmp, msg); g_free (tmp); g_free (msg); g_free (quotedname); return returncode; #endif /* not HAVE_REMOVE */ } bool_t rename_file_or_dir (const char *oldname, const char *newname) /* * Rename file 'oldname' to 'newname' (works like mv). * If the operation fails, show a popup error window. * * Return value: * FALSE on success, TRUE on error */ { #ifdef HAVE_RENAME if (rename (oldname, newname) == -1) { dialog_popup (DIALOG_ERROR, NULL, NULL, _("Can't move\n'%s'\nto\n'%s'\n\n%s"), oldname, newname, strerror (errno)); return YES; } else return NO; #else /* not HAVE_RENAME */ char *quotedoldname = protect_quotes (g_strdup (oldname)); char *quotednewname = protect_quotes (g_strdup (newname)); char *cmd = g_strconcat ("mv \"", quotedoldname, "\" \"", quotednewname, "\"", NULL); char *msg = g_strdup_printf (_("Can't move\n'%s'\nto\n'%s'"), oldname, newname); bool_t returncode; returncode = shell_command (cmd, msg); g_free (cmd); g_free (msg); g_free (quotednewname); g_free (quotedoldname); return returncode; #endif /* not HAVE_RENAME */ } bool_t remove_directory (const char *directory) /* * Recursively delete the given directory 'directory' with all its * files and subdirectories (works like rm -rf). * If the operation fails, show a popup error window. * * Return value: * FALSE on success, TRUE on error */ { DIR *dir = opendir (directory); if (!dir) /* a file */ return delete_file_or_dir (directory); else { struct dirent *file; while ((file = readdir (dir))) { if (!streq (file->d_name, ".") && !streq (file->d_name, "..")) { char *name = g_strconcat (directory, "/", file->d_name, NULL); if (remove_directory (name)) { closedir (dir); Free (name); return YES; }; Free (name); } } closedir (dir); return delete_file_or_dir (directory); } } bool_t make_directory (const char *dirname) /* * Create a nmew directory 'dirname' (works like mkdir). * If the operation fails, show a popup error window. * * Return value: * FALSE on success, TRUE on error */ { #if defined(HAVE_MKDIR) && defined(HAVE_SYS_STAT_H) if (mkdir (dirname, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH ) == -1) { dialog_popup (DIALOG_ERROR, NULL, NULL, _("Can't create directory\n'%s'\n\n%s"), dirname, strerror (errno)); return YES; } else return NO; #else /* not defined(HAVE_MKDIR) && defined(HAVE_SYS_STAT_H) */ char *quotedname = protect_quotes (g_strdup (dirname)); char *cmd = g_strconcat ("mkdir \"", quotedname, "\"", NULL); char *msg = g_strdup_printf (_("Can't create directory\n`%s'\n"), quotedname); returncode = shell_command (cmd, msg); g_free (cmd); g_free (msg); g_free (quotedname); return returncode; #endif /* not defined(HAVE_MKDIR) && defined(HAVE_SYS_STAT_H) */ } bool_t copy_file (const char *dst, const char *src) /* * Copy file 'src' to file or directory 'dst' (works like cp). * If the operation fails, show a popup error window. * * Return value: * FALSE on success, TRUE on error */ { if (!streq (src, dst)) { DIR *dir = opendir (dst); char *dst_name; FILE *fsrc; FILE *fdst; if (dir) /* directory is destination */ { closedir (dir); if (streq (dst, g_dirname (src))) return 0; dst_name = g_strconcat (dst, "/", g_basename (src), NULL); } else dst_name = g_strdup (dst); fsrc = fopen (src, "r"); if (!fsrc) { dialog_popup (DIALOG_ERROR, NULL, NULL, _("Can't open input file\n'%s'\n\n%s"), src, strerror (errno)); return YES; } fdst = fopen (dst_name, "w"); if (!fdst) { fclose (fsrc); dialog_popup (DIALOG_ERROR, NULL, NULL, _("Can't open output file\n'%s'\n\n%s"), dst_name, strerror (errno)); return YES; } { char buffer [4096]; size_t n; do { size_t m; n = fread (buffer, 1, 4096, fsrc); if (n) m = fwrite (buffer, 1, n, fdst); else m = 0; if (n != m) { fclose (fsrc); fclose (fdst); dialog_popup (DIALOG_ERROR, NULL, NULL, _("Can't write to output file\n'%s'\n\n%s"), dst_name, strerror (errno)); return YES; } } while (n == 4096); } fclose (fsrc); fclose (fdst); Free (dst_name); } return NO; } bool_t shell_command (const char *command, const char *text) /* * Execute shell 'command'. * If the operation fails, show a popup error window. * * Return value: * FALSE on success, TRUE on error */ { #if defined(HAVE_POPEN) extern GtkWidget *log_text; GtkTextBuffer *buffer; GtkTextIter iter; char *cmd = g_strconcat (command, " 2>&1", NULL); FILE *pipe = popen (cmd, "r"); char tmp [MAXSTRLEN]; Free (cmd); if (!pipe) { if (text) dialog_popup (DIALOG_ERROR, NULL, NULL, _("%s\nShell command failed.\n'%s'"), text, command); else dialog_popup (DIALOG_ERROR, NULL, NULL, _("Shell command failed.\n'%s'"), command); return YES; } buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (log_text)); while (fgets (tmp, MAXSTRLEN, pipe)) { gtk_text_buffer_get_iter_at_offset (buffer, &iter, -1); gtk_text_buffer_insert (buffer, &iter, tmp, -1); gtk_widget_show_all (gtk_widget_get_toplevel (log_text)); while (gtk_events_pending()) gtk_main_iteration(); } if (pclose (pipe)) { if (text) dialog_popup (DIALOG_ERROR, NULL, NULL, _("%s\nShell command failed.\n'%s'"), text, command); else dialog_popup (DIALOG_ERROR, NULL, NULL, _("Shell command failed.\n'%s'"), command); return YES; } else return NO; #else /* not HAVE_POPEN */ if (system (command)) { if (text) dialog_popup (DIALOG_ERROR, NULL, NULL, _("%s\nShell command failed.\n'%s'\n" "Please check `stderr' for more details."), text, command); else dialog_popup (DIALOG_ERROR, NULL, NULL, _("Shell command failed.\n'%s'\n" "Please check `stderr' for more details."), command); return YES; } else return NO; #endif /* not HAVE_POPEN */ } bool_t file_exists (const char *filename) /* * Checks whether a directory or file 'filename' already exists. * * Return value: * FALSE if file does not exist, TRUE if file exists */ { DIR *dir = opendir (filename); if (dir) /* directory exists */ { closedir (dir); return YES; } else { FILE *file = fopen (filename, "r"); if (!file) return NO; else { fclose (file); return YES; } } } char * preview_name (const char *name) /* * Compute the filename of the preview of the given image 'name'. * E.g., filename /path/to/foo.jpg is expanded to * ~/.wmakerconf-path-to-foo.jpg * * Return value: * preview filename */ { char *str = g_strdup (name); char *ptr, *path; for (ptr = str; *ptr; ptr++) if (*ptr == '/') *ptr = '-'; path = g_strconcat (g_get_home_dir (), "/.wmakerconf/", str, NULL); Free (str); return path; } proplist_t read_proplist (const char *filename) /* * Call Alfredo's PropList parser ... */ { DIR *dir = opendir (filename); if (dir) /* directory */ { closedir (dir); return NULL; } else return ReadProplistFromFile (filename); } char * protect_quotes (char *string) /* * Protect double quotes in the given string. * The old string is freed if it contains a double quote ". * * Return value: * new string with \" instead of " */ { char *pos; int offset = 0; while ((pos = strchr (string + offset, '"'))) { char *new; if (pos > string + offset) /* not first character */ { if (*(pos - 1) == '\\') /* if '\' is already present */ { offset = pos - string + 1; continue; } } offset = pos - string + 2; *pos = 0; new = g_strconcat (string, "\\\"", pos + 1, NULL); Free (string); string = new; } return string; }