/*
* misc.c: Miscellaneous functions
*
* Written by: Ullrich Hafner
*
* Copyright (C) 1998 Ullrich Hafner <hafner@bigfoot.de>
*
* 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 <stdlib.h>
#endif /* not HAVE_STDLIB_H */
#if HAVE_STRING_H
# include <string.h>
#else /* not HAVE_STRING_H */
# include <strings.h>
#endif /* not HAVE_STRING_H */
#if HAVE_SYS_TYPES_H
# include <sys/types.h>
#endif /* HAVE_SYS_TYPES_H */
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif /* HAVE_UNISTD_H */
#include <stdio.h>
#include <errno.h>
#include <gtk/gtk.h>
#include <pwd.h>
#if HAVE_SYS_STAT_H
# include <sys/stat.h>
#endif /* HAVE_SYS_STAT_H */
/* unistd.h defines _POSIX_VERSION on POSIX.1 systems. */
#if defined(HAVE_DIRENT_H) || defined(_POSIX_VERSION)
# include <dirent.h>
# define NLENGTH(dirent) (strlen ((dirent)->d_name))
#else
# define dirent direct
# define NLENGTH(dirent) ((dirent)->d_namlen)
# ifdef HAVE_SYS_NDIR_H
# include <sys/ndir.h>
# endif /* HAVE_SYS_NDIR_H */
# ifdef HAVE_SYS_DIR_H
# include <sys/dir.h>
# endif /* HAVE_SYS_DIR_H */
# ifdef HAVE_NDIR_H
# include <ndir.h>
# 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;
}
syntax highlighted by Code2HTML, v. 0.9.1