/* * 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 #include #include #include #include #include #include #include #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 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'; }