From 5442b754d70837d5fd8db1ee59a1649414f4bb77 Mon Sep 17 00:00:00 2001 From: "B. Watson" Date: Sun, 4 Feb 2024 17:14:39 -0500 Subject: Simplify option parsing. --- xdeadzone.c | 120 ++++++++++++++++++++++++++++++++---------------------------- 1 file changed, 65 insertions(+), 55 deletions(-) diff --git a/xdeadzone.c b/xdeadzone.c index 70d57cd..dc787d1 100644 --- a/xdeadzone.c +++ b/xdeadzone.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -27,9 +28,10 @@ # define DBG(x) #endif -enum { M_UNSET, M_ABS, M_NE, M_NW, M_SE, M_SW }; +const char *exe_name, *corner; -const char *exe_name; +#define GEOM_LEN 64 +char geom[GEOM_LEN+1]; void set_exe_name(const char *p) { exe_name = p; @@ -58,11 +60,6 @@ void errmsg(const char *msg) { usage(1); } -void check_mode(int mode) { - if(mode != M_ABS) - errmsg("multiple modes given, only one of -ne -nw -se -sw is allowed"); -} - int streq(const char *s1, const char *s2) { return !strcmp(s1, s2); } @@ -75,6 +72,39 @@ int ctrl_and_mod(unsigned int state) { return 0; } +void set_corner(const char *geom) { + if(corner) + errmsg("multiple modes given, only one of -ne -nw -se -sw is allowed"); + corner = geom; +} + +/* XParseGeometry doesn't do enough error checking. It'll allow + stuff like 100x100x100, or 100x100+foo, with no complaint. */ +void preparse_geom(const char *geom) { + int x_count = 0, plus_minus_count = 0, bogus_count = 0, len = 0; + const char *p = geom; + + while(*p) { + len++; + if(*p == 'x') + x_count++; + else if(*p == '+' || *p == '-') + plus_minus_count++; + else if(!isdigit(*p)) + bogus_count++; + p++; + } + + if(!x_count) + errmsg("bad geometry: no 'x' character"); + else if(x_count > 1) + errmsg("bad geometry: multiple 'x' characters"); + else if(plus_minus_count > 2) + errmsg("bad geometry: too many +/- characters"); + else if(bogus_count) + errmsg("bad geometry: invalid characters, only digits, +, -, x allowed"); +} + int main(int argc, char **argv) { Display *d; Window w; @@ -84,7 +114,7 @@ int main(int argc, char **argv) { XSetWindowAttributes setattr; XSizeHints hints; - int x = -1, y = -1, gflags = -1, visible = 0, black = 0, mode = M_ABS, normal_window = 0; + int x = -1, y = -1, gflags = -1, visible = 0, black = 0, normal_window = 0; unsigned int width, height; int new_x, new_y; @@ -109,53 +139,43 @@ int main(int argc, char **argv) { visible = 1; normal_window = 1; } else if(streq(a, "-ne")) { - check_mode(mode); - mode = M_NE; + set_corner("-0+0"); } else if(streq(a, "-nw")) { - check_mode(mode); - mode = M_NW; + set_corner("+0+0"); } else if(streq(a, "-se")) { - check_mode(mode); - mode = M_SE; + set_corner("-0-0"); } else if(streq(a, "-sw")) { - check_mode(mode); - mode = M_SW; + set_corner("+0-0"); } else if(a[0] == '-') { fprintf(stderr, "%s: invalid option: %s\n\n", exe_name, a); usage(1); } else { /* no dash, must be geometry */ - if(gflags == -1) - gflags = XParseGeometry(a, &x, &y, &width, &height); - else + if(geom[0]) errmsg("multiple geometry arguments given"); + else + strncpy(geom, a, GEOM_LEN); } } - if(gflags == -1) + if(!geom[0]) errmsg("missing required geometry argument"); - else - DBG(printf("XParseGeometry got %d %d %d %d\n", x, y, width, height)); - - if(mode != M_ABS && (gflags & (XValue | YValue))) - errmsg("bad geometry: X and Y position not allowed with -ne -nw -se -sw"); - - switch(mode) { - case M_ABS: - if(!(gflags & (XValue | YValue))) - errmsg("bad geometry: requires X and Y position or -ne -nw -se -sw"); - break; - case M_NW: - x = 0; y = 0; break; - case M_NE: - x = -width; y = 0; break; - case M_SW: - x = 0; y = -height; break; - case M_SE: - x = -width; y = -height; break; - default: - errmsg("invalid mode (internal logic error, this should never happen)"); + + if(corner) { + if(strchr(geom, '+') || strchr(geom, '-')) + errmsg("bad geometry: X and Y position not allowed with -ne -nw -se -sw"); + else + strncat(geom, corner, GEOM_LEN); } + preparse_geom(geom); + + gflags = XParseGeometry(geom, &x, &y, &width, &height); + + if(gflags == -1) + errmsg("bad geometry (failed to parse)"); + else + DBG(printf("XParseGeometry got %d %d %u %u\n", x, y, width, height)); + if(width == 0 || height == 0) errmsg("bad geometry: width and height must be non-zero"); @@ -163,24 +183,14 @@ int main(int argc, char **argv) { errmsg("can't open X display"); XGetWindowAttributes(d, DefaultRootWindow(d), &root_attr); - if(mode == M_ABS) { - if(gflags & XNegative) x = (root_attr.width + x) - width; - if(gflags & YNegative) y = (root_attr.height + y) - height; - } else { - if(x < 0) x = (root_attr.width + x); - if(y < 0) y = (root_attr.height + y); - } + if(gflags & XNegative) x = (root_attr.width + x) - width; + if(gflags & YNegative) y = (root_attr.height + y) - height; DBG(printf("X size %d x %d, x %d, y %d, width %d, height %d\n", root_attr.width, root_attr.height, x, y, width, height)); - /* Create window with override_redirect enabled, to tell the window - manager not to decorate it with a titlebar or resize frame. - Also, we really only care about EnterNotify events. - Set the window to solid white, to make it easy to see during testing. - In actual use, the window won't be visible, it'll be in the dead zone, - right? - */ + /* without -n, create window with override_redirect enabled, to tell the window + manager not to decorate it with a titlebar or resize frame. */ setattr.override_redirect = normal_window ? False : True; if(visible) { setattr.background_pixel = black ? -- cgit v1.2.3