summaryrefslogtreecommitdiff
path: root/cmd/wmii/_util.c
diff options
context:
space:
mode:
Diffstat (limited to 'cmd/wmii/_util.c')
-rw-r--r--cmd/wmii/_util.c378
1 files changed, 378 insertions, 0 deletions
diff --git a/cmd/wmii/_util.c b/cmd/wmii/_util.c
new file mode 100644
index 0000000..feafba9
--- /dev/null
+++ b/cmd/wmii/_util.c
@@ -0,0 +1,378 @@
+/* Copyright ©2008-2010 Kris Maglione <maglione.k at Gmail>
+ * See LICENSE file for license details.
+ */
+#include "dat.h"
+#include <errno.h>
+#include <fcntl.h>
+#include <stdarg.h>
+#include <sys/signal.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <bio.h>
+#include "fns.h"
+
+/* Blech. */
+#define VECTOR(type, nam, c) \
+void \
+vector_##c##init(Vector_##nam *v) { \
+ memset(v, 0, sizeof *v); \
+} \
+ \
+void \
+vector_##c##free(Vector_##nam *v) { \
+ free(v->ary); \
+ memset(v, 0, sizeof *v); \
+} \
+ \
+void \
+vector_##c##push(Vector_##nam *v, type val) { \
+ if(v->n == v->size) { \
+ if(v->size == 0) \
+ v->size = 2; \
+ v->size <<= 2; \
+ v->ary = erealloc(v->ary, v->size * sizeof *v->ary); \
+ } \
+ v->ary[v->n++] = val; \
+} \
+
+VECTOR(long, long, l)
+VECTOR(Rectangle, rect, r)
+VECTOR(void*, ptr, p)
+
+int
+doublefork(void) {
+ pid_t pid;
+ int status;
+
+ switch(pid=fork()) {
+ case -1:
+ fatal("Can't fork(): %r");
+ case 0:
+ switch(pid=fork()) {
+ case -1:
+ fatal("Can't fork(): %r");
+ case 0:
+ return 0;
+ default:
+ exit(0);
+ }
+ default:
+ waitpid(pid, &status, 0);
+ return pid;
+ }
+ /* NOTREACHED */
+}
+
+void
+closeexec(int fd) {
+ if(fcntl(fd, F_SETFD, FD_CLOEXEC) == -1)
+ fatal("can't set %d close on exec: %r", fd);
+}
+
+int
+spawn3(int fd[3], const char *file, char *argv[]) {
+ /* Some ideas from Russ Cox's libthread port. */
+ int p[2];
+ int pid;
+
+ if(pipe(p) < 0)
+ return -1;
+ closeexec(p[1]);
+
+ switch(pid = doublefork()) {
+ case 0:
+ dup2(fd[0], 0);
+ dup2(fd[1], 1);
+ dup2(fd[2], 2);
+
+ execvp(file, argv);
+ write(p[1], &errno, sizeof errno);
+ exit(1);
+ break;
+ default:
+ close(p[1]);
+ if(read(p[0], &errno, sizeof errno) == sizeof errno)
+ pid = -1;
+ close(p[0]);
+ break;
+ case -1: /* can't happen */
+ break;
+ }
+
+ close(fd[0]);
+ /* These could fail if any of these was also a previous fd. */
+ close(fd[1]);
+ close(fd[2]);
+ return pid;
+}
+
+int
+spawn3l(int fd[3], const char *file, ...) {
+ va_list ap;
+ char **argv;
+ int i, n;
+
+ va_start(ap, file);
+ for(n=0; va_arg(ap, char*); n++)
+ ;
+ va_end(ap);
+
+ argv = emalloc((n+1) * sizeof *argv);
+ va_start(ap, file);
+ quotefmtinstall();
+ for(i=0; i <= n; i++)
+ argv[i] = va_arg(ap, char*);
+ va_end(ap);
+
+ i = spawn3(fd, file, argv);
+ free(argv);
+ return i;
+}
+
+#ifdef __linux__
+# define PROGTXT "exe"
+#else
+# define PROGTXT "file"
+#endif
+
+static void
+_backtrace(int pid, char *btarg) {
+ char *proc, *spid, *gdbcmd;
+ int fd[3], p[2];
+ int status, cmdfd;
+
+ gdbcmd = estrdup("/tmp/gdbcmd.XXXXXX");
+ if(pipe(p) < 0)
+ goto done;
+ closeexec(p[0]);
+
+ cmdfd = mkstemp(gdbcmd);
+ if(cmdfd < 0)
+ goto done;
+
+ fprint(cmdfd, "bt %s\n", btarg);
+ fprint(cmdfd, "detach\n");
+ close(cmdfd);
+
+ fd[0] = open("/dev/null", O_RDONLY);
+ fd[1] = p[1];
+ fd[2] = dup(2);
+
+ proc = sxprint("/proc/%d/" PROGTXT, pid);
+ spid = sxprint("%d", pid);
+ if(spawn3l(fd, "gdb", "gdb", "-batch", "-x", gdbcmd, proc, spid, nil) < 0) {
+ unlink(gdbcmd);
+ goto done;
+ }
+
+ Biobuf bp;
+ char *s;
+
+ Binit(&bp, p[0], OREAD);
+ while((s = Brdstr(&bp, '\n', 1))) {
+ Dprint(DStack, "%s\n", s);
+ free(s);
+ }
+ unlink(gdbcmd);
+
+done:
+ free(gdbcmd);
+ kill(pid, SIGKILL);
+ waitpid(pid, &status, 0);
+}
+
+void
+backtrace(char *btarg) {
+ int pid;
+
+ /* Fork so we can backtrace the child. Keep this stack
+ * frame minimal, so the trace is fairly clean.
+ */
+ Debug(DStack)
+ switch(pid = fork()) {
+ case -1:
+ return;
+ case 0:
+ kill(getpid(), SIGSTOP);
+ _exit(0);
+ default:
+ _backtrace(pid, btarg);
+ break;
+ }
+
+}
+
+void
+reinit(Regex *r, char *regx) {
+
+ refree(r);
+
+ if(regx[0] != '\0') {
+ r->regex = estrdup(regx);
+ r->regc = regcomp(regx);
+ }
+}
+
+void
+refree(Regex *r) {
+
+ free(r->regex);
+ free(r->regc);
+ r->regex = nil;
+ r->regc = nil;
+}
+
+void
+uniq(char **toks) {
+ char **p, **q;
+
+ q = toks;
+ if(*q == nil)
+ return;
+ for(p=q+1; *p; p++)
+ if(strcmp(*q, *p))
+ *++q = *p;
+ *++q = nil;
+}
+
+char**
+comm(int cols, char **toka, char **tokb) {
+ Vector_ptr vec;
+ char **ret;
+ int cmp;
+
+ vector_pinit(&vec);
+ while(*toka || *tokb) {
+ if(!*toka)
+ cmp = 1;
+ else if(!*tokb)
+ cmp = -1;
+ else
+ cmp = strcmp(*toka, *tokb);
+ if(cmp < 0) {
+ if(cols & CLeft)
+ vector_ppush(&vec, *toka);
+ toka++;
+ }else if(cmp > 0) {
+ if(cols & CRight)
+ vector_ppush(&vec, *tokb);
+ tokb++;
+ }else {
+ if(cols & CCenter)
+ vector_ppush(&vec, *toka);
+ toka++;
+ tokb++;
+ }
+ }
+ vector_ppush(&vec, nil);
+ ret = strlistdup((char**)vec.ary);
+ free(vec.ary);
+ return ret;
+}
+
+void
+grep(char **list, Reprog *re, int flags) {
+ char **p, **q;
+ int res;
+
+ q = list;
+ for(p=q; *p; p++) {
+ res = 0;
+ if(re)
+ res = regexec(re, *p, nil, 0);
+ if(res && !(flags & GInvert)
+ || !res && (flags & GInvert))
+ *q++ = *p;
+ }
+ *q = nil;
+}
+
+char*
+join(char **list, char *sep) {
+ Fmt f;
+ char **p;
+
+ if(fmtstrinit(&f) < 0)
+ abort();
+
+ for(p=list; *p; p++) {
+ if(p != list)
+ fmtstrcpy(&f, sep);
+ fmtstrcpy(&f, *p);
+ }
+
+ return fmtstrflush(&f);
+}
+
+int
+strlcatprint(char *buf, int len, const char *fmt, ...) {
+ va_list ap;
+ int buflen;
+ int ret;
+
+ va_start(ap, fmt);
+ buflen = strlen(buf);
+ ret = vsnprint(buf+buflen, len-buflen, fmt, ap);
+ va_end(ap);
+ return ret;
+}
+
+char*
+pathsearch(const char *path, const char *file, bool slashok) {
+ char *orig, *p, *s;
+
+ if(!slashok && strchr(file, '/') > file)
+ file = sxprint("%s/%s", getcwd(buffer, sizeof buffer), file);
+ else if(!strncmp(file, "./", 2))
+ file = sxprint("%s/%s", getcwd(buffer, sizeof buffer), file+2);
+ if(file[0] == '/') {
+ if(access(file, X_OK))
+ return strdup(file);
+ return nil;
+ }
+
+ orig = estrdup(path ? path : getenv("PATH"));
+ for(p=orig; (s=strtok(p, ":")); p=nil) {
+ s = smprint("%s/%s", s, file);
+ if(!access(s, X_OK))
+ break;
+ free(s);
+ }
+ free(orig);
+ return s;
+}
+
+int
+unquote(char *buf, char *toks[], int ntoks) {
+ char *s, *t;
+ bool inquote;
+ int n;
+
+ n = 0;
+ s = buf;
+ while(*s && n < ntoks) {
+ while(*s && utfrune(" \t\r\n", *s))
+ s++;
+ inquote = false;
+ toks[n] = s;
+ t = s;
+ while(*s && (inquote || !utfrune(" \t\r\n", *s))) {
+ if(*s == '\'') {
+ if(inquote && s[1] == '\'')
+ *t++ = *s++;
+ else
+ inquote = !inquote;
+ }
+ else
+ *t++ = *s;
+ s++;
+ }
+ if(*s)
+ s++;
+ *t = '\0';
+ if(s != toks[n])
+ n++;
+ }
+ return n;
+}
+