/*
* WMMail - Window Maker Mail
*
* wmutil.c: WMMail miscellaneous function library, ripped from
* Alfredo Kojima's Window Maker (http://www.windowmaker.org)
*
* Window Maker miscellaneous function library
*
* Copyright (c) 1997 Alfredo K. Kojima
* Modifications Copyright (c) 1998 Bryan Chan
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: wmutil.c.in,v 1.1 2000/07/02 20:39:17 bryan.chan Exp $
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <pwd.h>
#include <limits.h>
#include "list.h"
extern int keep_quiet; /* defined in global.c */
extern char *app_name; /* defined in global.c */
static char *get_user_home_dir(char *);
static char *check_file(char *, char *, char *);
static char *next_token(char *, char **);
static void parse_command(char *, char ***, int *);
#define MAX_ERRORMSG_LENGTH 256
void croak(char *fmt,...)
{
va_list arg_ptr;
static char buf[MAX_ERRORMSG_LENGTH];
if (keep_quiet)
return;
va_start(arg_ptr, fmt);
vsprintf(buf, fmt, arg_ptr);
strcat(buf, "\n");
fflush(stdout);
fputs(app_name, stderr);
fputs(": ", stderr);
fputs(buf, stderr);
fflush(stdout);
fflush(stderr);
va_end(arg_ptr);
}
void *wmalloc(size_t size)
{
void *tmp;
tmp = calloc(1, size);
if (tmp == NULL)
{
croak("wmalloc() failed; retrying after 2 seconds");
sleep(2);
tmp = calloc(1, size);
if (tmp == NULL)
{
croak("virtual memory exhausted");
exit(-1);
}
}
return tmp;
}
void *wrealloc(void *ptr, size_t newsize)
{
void *nptr;
if (!ptr)
nptr = calloc (1, newsize);
else
nptr = realloc(ptr, newsize);
if (nptr==NULL)
{
croak("wrealloc() failed");
return NULL;
}
return nptr;
}
inline void wfree(void *ptr)
{
if (ptr != NULL)
free(ptr);
}
char *wstrdup(char *str)
{
if (str == NULL)
return NULL;
return strcpy(wmalloc(strlen(str) + 1), str);
}
char *get_home_dir()
{
char *home = getenv("HOME");
struct passwd *user;
if (home)
return home;
if ( !(user = getpwuid(getuid())) )
{
croak("cannot get password entry for UID %i", getuid());
return "/";
}
if (!user->pw_dir)
return "/";
else
return user->pw_dir;
}
static char *get_user_home_dir(char *username)
{
struct passwd *user;
if ( !(user = getpwnam(username)) )
{
croak("cannot get password entry for user %s", username);
return NULL;
}
if (!user->pw_dir)
return "/";
else
return user->pw_dir;
}
char *expand_path(char *path)
{
char buffer2[PATH_MAX+2];
char buffer[PATH_MAX+2];
int i;
memset(buffer, 0, PATH_MAX+2);
if (*path=='~')
{
char *home;
path++;
if (*path=='/' || *path==0)
{
home = get_home_dir();
strcat(buffer, home);
}
else
{
int j;
j = 0;
while (*path!=0 && *path!='/')
{
buffer2[j++] = *path;
buffer2[j] = 0;
path++;
}
home = get_user_home_dir(buffer2);
if (!home)
return NULL;
strcat(buffer, home);
}
}
i = strlen(buffer);
while (*path!=0)
{
char *tmp;
if (*path=='$')
{
int j = 0;
path++;
/* expand $(HOME) or $HOME style environment variables */
if (*path=='(')
{
path++;
while (*path!=0 && *path!=')')
{
buffer2[j++] = *(path++);
buffer2[j] = 0;
}
if (*path==')')
path++;
tmp = getenv(buffer2);
if (!tmp)
{
buffer[i] = 0;
strcat(buffer, "$(");
strcat(buffer, buffer2);
strcat(buffer, ")");
i += strlen(buffer2)+3;
}
else
{
strcat(buffer, tmp);
i += strlen(tmp);
}
}
else
{
while (*path!=0 && *path!='/')
{
buffer2[j++] = *(path++);
buffer2[j] = 0;
}
tmp = getenv(buffer2);
if (!tmp)
{
strcat(buffer, "$");
strcat(buffer, buffer2);
i += strlen(buffer2)+1;
}
else
{
strcat(buffer, tmp);
i += strlen(tmp);
}
}
}
else
{
buffer[i++] = *path;
path++;
}
}
return wstrdup(buffer);
}
char *find_resource(char *resource, char *folders)
{
char *prefix, *path;
/* try to find resources in the following locations (in order):
*
* 1. $GNUSTEP_USER_ROOT/folders/resource
* 2. ~/GNUstep/folders/resource
* 3. $GNUSTEP_LOCAL_ROOT/folders/resource
* 4. /usr/local/GNUstep/folders/resource
* 5. /usr/X11R6/GNUstep/folders/resource
* 6. $GNUSTEP_SYSTEM_ROOT/folders/resource
* 7. /usr/GNUstep/folders/resource
*/
if (prefix = getenv("GNUSTEP_USER_ROOT"))
if (path = check_file(prefix, folders, resource))
return path;
if (get_home_dir())
{
prefix = wmalloc(strlen(get_home_dir()) + 9);
strcpy(prefix, get_home_dir());
strcat(prefix, "/GNUstep");
if (path = check_file(prefix, folders, resource))
{
wfree(prefix);
return path;
}
else
wfree(prefix);
}
if (prefix = getenv("GNUSTEP_LOCAL_ROOT"))
if (path = check_file(prefix, folders, resource))
return path;
if (path = check_file("/usr/X11R6/GNUstep", folders, resource))
return path;
if (path = check_file("/usr/local/GNUstep", folders, resource))
return path;
if (prefix = getenv("GNUSTEP_SYSTEM_ROOT"))
if (path = check_file(prefix, folders, resource))
return path;
if (path = check_file("/usr/GNUstep", folders, resource))
return path;
return (char *) NULL;
}
static char *check_file(char *path, char *folders, char *resource)
{
char *buf;
int bufsize;
bufsize = strlen(path) + strlen(resource) + (folders ? strlen(folders) : 0);
bufsize += 3; /* account for slashes and terminating NULL */
buf = (char *) wmalloc(bufsize);
strcpy(buf, path);
if (folders)
{
strcat(buf, "/");
strcat(buf, folders);
}
strcat(buf, "/");
strcat(buf, resource);
#ifdef DEBUG
croak("checking %s", buf);
#endif
if (access(buf, F_OK) != 0)
{
wfree(buf);
buf = NULL;
}
return buf;
}
pid_t exec_command(char *command)
{
pid_t pid;
char **argv;
int argc;
parse_command(command, &argv, &argc);
if (argv==NULL)
return 0;
if ((pid=fork())==0)
{
char **args;
int i;
#ifdef HAVE_SETPGID
setpgid(0, 0);
#endif
args = malloc(sizeof(char*)*(argc+1));
if (!args)
exit(111);
for (i=0; i<argc; i++)
args[i] = argv[i];
args[argc] = NULL;
execvp(argv[0], args);
exit(111);
}
while (argc > 0)
wfree(argv[--argc]);
wfree(argv);
return pid;
}
/* parse_command: divides a command line into a argv/argc pair */
#define PRC_ALPHA 0
#define PRC_BLANK 1
#define PRC_ESCAPE 2
#define PRC_DQUOTE 3
#define PRC_EOS 4
#define PRC_SQUOTE 5
typedef struct {
short nstate;
short output;
} DFA;
static DFA mtable[9][6] = {
{{3,1},{0,0},{4,0},{1,0},{8,0},{6,0}},
{{1,1},{1,1},{2,0},{3,0},{5,0},{1,1}},
{{1,1},{1,1},{1,1},{1,1},{5,0},{1,1}},
{{3,1},{5,0},{4,0},{1,0},{5,0},{6,0}},
{{3,1},{3,1},{3,1},{3,1},{5,0},{3,1}},
{{-1,-1},{0,0},{0,0},{0,0},{0,0},{0,0}}, /* final state */
{{6,1},{6,1},{7,0},{6,1},{5,0},{3,0}},
{{6,1},{6,1},{6,1},{6,1},{5,0},{6,1}},
{{-1,-1},{0,0},{0,0},{0,0},{0,0},{0,0}}, /* final state */
};
static char* next_token(char *word, char **next)
{
char *ptr;
char *ret, *t;
int state, ctype;
t = ret = wmalloc(strlen(word)+1);
ptr = word;
state = 0;
*t = 0;
while (1)
{
if (*ptr==0)
ctype = PRC_EOS;
else if (*ptr=='\\')
ctype = PRC_ESCAPE;
else if (*ptr=='"')
ctype = PRC_DQUOTE;
else if (*ptr=='\'')
ctype = PRC_SQUOTE;
else if (*ptr==' ' || *ptr=='\t')
ctype = PRC_BLANK;
else
ctype = PRC_ALPHA;
if (mtable[state][ctype].output)
{
*t = *ptr; t++;
*t = 0;
}
state = mtable[state][ctype].nstate;
ptr++;
if (mtable[state][0].output<0)
break;
}
if (*ret==0)
t = NULL;
else
t = wstrdup(ret);
wfree(ret);
if (ctype==PRC_EOS)
*next = NULL;
else
*next = ptr;
return t;
}
static void parse_command(char *command, char ***argv, int *argc)
{
LinkedList *list = NULL;
char *token, *line;
int count, i;
line = command;
do
{
token = next_token(line, &line);
if (token)
list = list_cons(token, list);
} while (token!=NULL && line!=NULL);
count = list_length(list);
*argv = wmalloc(sizeof(char*)*count);
i = count;
while (list!=NULL)
{
(*argv)[--i] = list->head;
list_remove_head(&list);
}
*argc = count;
}
void unescape(char *s)
{
int i, j;
for (i = 0, j = 0; s[j] != '\0'; i++, j++)
{
if (s[j] != '\\')
s[i] = s[j];
else
s[i] = s[++j];
}
s[i] = '\0';
}
syntax highlighted by Code2HTML, v. 0.9.1