commit c3b838c4f16762953b3bed16da031c88703fe2b1
parent 8958a15d5cace30f3bb2a49b5ff77b6cf9f0a9cc
Author: Louis Burda <quent.burda@gmail.com>
Date: Tue, 14 Mar 2023 01:16:59 +0100
Improve commandline interface
Diffstat:
M | Makefile | | | 2 | +- |
M | loader.c | | | 173 | +++++++++++++++++++++++++++++++++++++++++++++++++++---------------------------- |
2 files changed, 112 insertions(+), 63 deletions(-)
diff --git a/Makefile b/Makefile
@@ -1,7 +1,7 @@
PREFIX ?= /usr/local
BINDIR ?= /bin
-CFLAGS = --std=gnu99 -Wmissing-prototypes -Wunused-variable -g
+CFLAGS = -Wunused-variable -Wunused-function -g
LIB_FLAGS = $(CFLAGS) -nostartfiles -fPIC -shared -Wl,-soname,xwrap.so
LOADER_FLAGS = $(CFLAGS)
LDLIBS = -ldl -lX11 -lXinerama
diff --git a/loader.c b/loader.c
@@ -1,77 +1,96 @@
-#include <stdlib.h>
-#include <stdbool.h>
+#include <linux/limits.h>
+#include <sys/stat.h>
+#include <err.h>
+#include <dirent.h>
+#include <limits.h>
+#include <unistd.h>
#include <string.h>
#include <stdio.h>
-#include <unistd.h>
-#include <sys/stat.h>
+#include <stdbool.h>
+#include <stdlib.h>
#define ARRLEN(x) (sizeof(x) / sizeof((x)[0]))
-#define ERROR(msg) { fprintf(stderr, "winpl: %s\n", msg); exit(1); }
+static const char *libpath = "/tmp/winpl.so";
extern char _binary_winpl_so_start[];
extern char _binary_winpl_so_end[];
extern char **environ;
-static void write_lib(const char *filename);
-static bool parse_arg(const char *arg);
-
-static const char *conv[][2] = {
- { "ax:", "WINPL_WX" },
- { "ay:", "WINPL_WY" },
- { "rx:", "WINPL_RWX" },
- { "ry:", "WINPL_RWY" },
- { "x:", "WINPL_MWX" },
- { "y:", "WINPL_MWY" },
- { "w:", "WINPL_WW" },
- { "h:", "WINPL_WH" },
- { "rw:", "WINPL_RWW" },
- { "rh:", "WINPL_RWH" },
- { "center", "WINPL_CENTER" },
- { "float", "WINPL_FLOAT" },
- { "screen:", "WINPL_SCREEN_NUM" },
- { "pointer", "WINPL_SCREEN_PTR" },
-};
+void
+usage(int rc, bool full)
+{
+ fprintf(stderr, "Usage: winpl [OPT].. -- CMD [ARG]..\n");
+ if (!full) exit(rc);
+ fprintf(stderr, "\n");
+ fprintf(stderr, " [-ax|-ay] POS Absolute window position\n");
+ fprintf(stderr, " [-mx|-my] POS Window position relative to monitor\n");
+ fprintf(stderr, " [-rx|-ry] SCALE Window position relative to monitor\n"
+ " as a factor of monitor size\n");
+ fprintf(stderr, " [-aw|-ah] SIZE Absolute window width/height\n");
+ fprintf(stderr, " [-rw|-rh] SCALE Window size relative to monitor\n");
+ fprintf(stderr, " -c Center window on monitor\n");
+ fprintf(stderr, " -f Tag window as dialog (floating)\n");
+ fprintf(stderr, " -sn SCREEN Select monitor based on number\n");
+ fprintf(stderr, " -sp Select monitor based on cursor\n");
+ fprintf(stderr, "\n");
+ exit(rc);
+}
void
write_lib(const char *filename)
{
FILE *file;
+ size_t size;
void *data;
- size_t expected, actual;
- file = fopen(filename, "w+");
- if (!file) ERROR("Failed to create temp file");
+ file = fopen(filename, "wb+");
+ if (!file) err(1, "fopen %s", filename);
data = (void*) _binary_winpl_so_start;
- expected = (size_t) (_binary_winpl_so_end - _binary_winpl_so_start);
+ size = (size_t) (_binary_winpl_so_end - _binary_winpl_so_start);
- actual = fwrite(data, 1, expected, file);
- if (actual != expected) ERROR("Failed to write temp file");
+ if (fwrite(data, size, 1, file) != 1)
+ errx(1, "failed to write winpl lib");
fclose(file);
}
bool
-parse_arg(const char *arg)
+find_bin(char *pathbuf, const char *bin)
{
- int i, len;
-
- for (i = 0; i < ARRLEN(conv); i++) {
- len = strlen(conv[i][0]);
- if (strncmp(arg, conv[i][0], len))
- continue;
-
- if (conv[i][0][len-1] == ':') {
- setenv(conv[i][1], arg + len, true);
- } else if (!arg[len]) {
- setenv(conv[i][1], "1", true);
- } else {
- return false;;
+ char tmp[PATH_MAX];
+ const char *env_path;
+ const char *tok, *start, *end;
+ struct dirent *ent;
+ DIR *dir;
+
+ env_path = getenv("PATH");
+ if (!env_path) return false;
+
+ start = tok = env_path;
+ while (tok) {
+ tok = strchr(start, ':');
+ if (!tok) end = start + strlen(start);
+ else end = tok;
+
+ snprintf(tmp, PATH_MAX, "%.*s", (int) (end - start), start);
+ dir = opendir(tmp);
+ if (!dir) goto next;
+
+ while ((ent = readdir(dir))) {
+ if (!strcmp(ent->d_name, bin)) {
+ snprintf(pathbuf, PATH_MAX, "%s/%s",
+ tmp, ent->d_name);
+ return true;
+ }
}
- return true;
+ closedir(dir);
+
+next:
+ start = tok + 1;
}
return false;
@@ -80,33 +99,63 @@ parse_arg(const char *arg)
int
main(int argc, char *const *argv)
{
- char *tmpfile = "/tmp/winpl.so";
+ char *const *arg, *const *cmd_argv;
+ char pathbuf[PATH_MAX];
struct stat st;
- char *const *arg, *const *cmd;
+ int rc;
if (argc < 1) return 0;
- cmd = NULL;
+ cmd_argv = NULL;
for (arg = argv + 1; *arg; arg++) {
- if (!strcmp(*arg, "--") && *(arg+1)) {
- cmd = arg + 1;
+ if (!strcmp(*arg, "-h")) {
+ usage(0, true);
+ } else if (!strcmp(*arg, "-ax")) {
+ setenv("WINPL_WX", *++arg, true);
+ } else if (!strcmp(*arg, "-ay")) {
+ setenv("WINPL_WY", *++arg, true);
+ } else if (!strcmp(*arg, "-mx")) {
+ setenv("WINPL_MWX", *++arg, true);
+ } else if (!strcmp(*arg, "-my")) {
+ setenv("WINPL_MWY", *++arg, true);
+ } else if (!strcmp(*arg, "-rx")) {
+ setenv("WINPL_RWX", *++arg, true);
+ } else if (!strcmp(*arg, "-ry")) {
+ setenv("WINPL_RWY", *++arg, true);
+ } else if (!strcmp(*arg, "-aw")) {
+ setenv("WINPL_WW", *++arg, true);
+ } else if (!strcmp(*arg, "-ah")) {
+ setenv("WINPL_WH", *++arg, true);
+ } else if (!strcmp(*arg, "-rw")) {
+ setenv("WINPL_RWW", *++arg, true);
+ } else if (!strcmp(*arg, "-rh")) {
+ setenv("WINPL_RWH", *++arg, true);
+ } else if (!strcmp(*arg, "-c")) {
+ setenv("WINPL_CENTER", "1", true);
+ } else if (!strcmp(*arg, "-f")) {
+ setenv("WINPL_FLOAT", "1", true);
+ } else if (!strcmp(*arg, "-sn")) {
+ setenv("WINPL_SCREEN_NUM", *++arg, true);
+ } else if (!strcmp(*arg, "-sp")) {
+ setenv("WINPL_SCREEN_PTR", "1", true);
+ } else if (!strcmp(*arg, "--") && *(arg+1)) {
+ cmd_argv = arg + 1;
break;
+ } else {
+ usage(1, true);
}
-
- if (!parse_arg(*arg))
- ERROR("Invalid argument");
}
+ if (cmd_argv == NULL)
+ usage(1, false);
- if (cmd == NULL)
- ERROR("Missing args separator");
-
- if (stat(*cmd, &st))
- ERROR("Binary not full path");
+ if (stat(libpath, &st))
+ write_lib(libpath);
- if (stat(tmpfile, &st))
- write_lib(tmpfile);
+ setenv("LD_PRELOAD", libpath, true);
- setenv("LD_PRELOAD", tmpfile, true);
+ if (!find_bin(pathbuf, *cmd_argv))
+ errx(1, "Binary not in PATH: %s", *cmd_argv);
- execve(*cmd, cmd, environ);
+ rc = execve(pathbuf, cmd_argv, environ);
+ if (rc) err(1, "execve %s", pathbuf);
}