Current-Users archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
Re: [patch] give gpioctl.c some love
Am 22.08.15 um 02:22 schrieb Timo Buhrmester:
> I was troubleshooting a GPIO problem and came across usr.sbin/gpioctl/gpioctl.c. The code is well-written, but I figured it needs some love, readability-wise. It uses unnecessarily deep nesting while trying to stay witin 80 characters per line at tabstop 8; I refactored parts of it to eliminate that problem (maintaining the 80-colums invariant, of course).
>
> Apart from that, a few other things were changed here and there:
> - const correctness
> - meaningful prototypes
> - avoidance of redundancies
> - fix (and isolate) converting a string to `unsigned` (it errorneously accepted some negative values before, and didn't zero/restore errno (not that it has restore, but it certainly is good manners to do)
> - declutter main() a bit
>
> Overall, a patch that removes (slightly) more lines than it adds, so it must be good, no? :)
> I'll inline it here for easier commenting, if there are objections.
as the original author of gpioctl I add my comments inline.... I am
mostly against this patch, but to make it clear: that is not against
you, but against the patch ;)
Imo, this patch does not solve a problem, but creates new ones, maybe...
The constness that you sprinkle is definitely not needed, only makes
the code cluttered imo.
>
>
> Cheers,
>
> Timo Buhrmester
>
> P.S.: gpioctl's functionality or behavior is not changed, apart from the integer parsing issue (a missing `lval < 0`)
>
>
> ----------8<---------------------------------------------------------
>
> --- usr.sbin/gpioctl/gpioctl.c.orig
> +++ usr.sbin/gpioctl/gpioctl.c
> @@ -36,17 +36,21 @@
> #include <string.h>
> #include <unistd.h>
>
> -static char *dev;
> +static const char *dev;
> static int devfd = -1;
> static int quiet = 0;
> static int state = 0;
>
> static void getinfo(void);
> -static void gpioread(int, char *);
> -static void gpiowrite(int, char *, int);
> -static void gpioset(int pin, char *name, int flags, char *alias);
> -static void gpiounset(int pin, char *name);
> -static void devattach(char *, int, uint32_t, uint32_t);
> +static void gpioread(int pin, const char *gp_name);
> +static void gpiowrite(int pin, const char *gp_name, int value);
> +static void gpioset(int pin, const char *name, int flags, const char *alias);
> +static void gpiounset(int pin, const char *name);
> +
> +static unsigned get_uint_or_die(const char *str, const char *name);
> +static void devattach(const char *driver, const char *offset,
> + const char *mask, const char *flags);
> +
This is wrong. We don't use variable names in function prototypes for
good reason.
> __dead static void usage(void);
>
> static const struct bitstr {
> @@ -67,19 +71,14 @@ static const struct bitstr {
> { 0, NULL },
> };
>
> +
What does it gain you to add an empty line here?
> int
> main(int argc, char *argv[])
> {
> const struct bitstr *bs;
> int pin, ch, n, fl = 0, value = 0;
> const char *errstr;
> - char *ep;
> - int ga_offset = -1;
> - uint32_t ga_mask = 0;
> - uint32_t ga_flags = 0;
> - long lval;
> char *nam = NULL;
> - char *flags;
> char devn[32];
>
> while ((ch = getopt(argc, argv, "qs")) != -1)
> @@ -115,84 +114,54 @@ main(int argc, char *argv[])
> }
>
> if (!strcmp(argv[1], "attach")) {
> - char *driver, *offset, *mask;
> -
> if (argc != 5 && argc != 6)
> usage();
>
> - driver = argv[2];
> - offset = argv[3];
> - mask = argv[4];
> - flags = argc == 6 ? argv[5] : NULL;
> -
> - ga_offset = strtonum(offset, 0, INT_MAX, &errstr);
> - if (errstr)
> - errx(EXIT_FAILURE, "offset is %s: %s", errstr, offset);
> - lval = strtol(mask, &ep, 0);
> - if (*mask == '\0' || *ep != '\0')
> - errx(EXIT_FAILURE, "invalid mask (not a number)");
> - if ((errno == ERANGE && (lval == LONG_MAX
> - || lval == LONG_MIN)) || (unsigned long)lval > UINT_MAX)
> - errx(EXIT_FAILURE, "mask out of range");
> - ga_mask = lval;
> - if (flags != NULL) {
> - lval = strtol(flags, &ep, 0);
> - if (*flags == '\0' || *ep != '\0')
> - errx(EXIT_FAILURE,
> - "invalid flag locator (not a number)");
> - if ((errno == ERANGE && (lval == LONG_MAX
> - || lval == LONG_MIN))
> - || (unsigned long)lval > UINT_MAX)
> - errx(EXIT_FAILURE, "flag locator out of range");
> -
> - ga_flags = lval;
> - }
> - devattach(driver, ga_offset, ga_mask, ga_flags);
> + devattach(argv[2], argv[3], argv[4], argv[5]);
> +
> return EXIT_SUCCESS;
> - } else {
> - char *nm = NULL;
> -
> - /* expecting a pin number or name */
> - pin = strtonum(argv[1], 0, INT_MAX, &errstr);
> - if (errstr)
> - nm = argv[1]; /* try named pin */
> - if (argc > 2) {
> - if (!strcmp(argv[2], "set")) {
> - for (n = 3; n < argc; n++) {
> - for (bs = pinflags; bs->string != NULL;
> - bs++) {
> - if (!strcmp(argv[n],
> - bs->string)) {
> - fl |= bs->mask;
> - break;
> - }
> - }
> - if (bs->string == NULL)
> - nam = argv[n];
> - }
> - gpioset(pin, nm, fl, nam);
> - } else if (!strcmp(argv[2], "unset"))
> - gpiounset(pin, nm);
> - else {
> - value = strtonum(argv[2], INT_MIN, INT_MAX,
> - &errstr);
> - if (errstr) {
> - if (!strcmp(argv[2], "on"))
> - value = GPIO_PIN_HIGH;
> - else if (!strcmp(argv[2], "off"))
> - value = GPIO_PIN_LOW;
> - else if (!strcmp(argv[2], "toggle"))
> - value = 2;
> - else
> - errx(EXIT_FAILURE,
> - "%s: invalid value",
> - argv[2]);
> + }
> +
> + char *nm = NULL;
> + /* expecting a pin number or name */
> + pin = strtonum(argv[1], 0, INT_MAX, &errstr);
> + if (errstr)
> + nm = argv[1]; /* try named pin */
> +
> + if (argc <= 2) {
> + gpioread(pin, nm);
> + return EXIT_SUCCESS;
> + }
> +
> + if (!strcmp(argv[2], "set")) {
> + for (n = 3; n < argc; n++) {
> + for (bs = pinflags; bs->string; bs++) {
> + if (!strcmp(argv[n], bs->string)) {
> + fl |= bs->mask;
> + break;
> }
> - gpiowrite(pin, nm, value);
> }
> - } else
> - gpioread(pin, nm);
> + if (!bs->string)
> + nam = argv[n];
> + }
> + gpioset(pin, nm, fl, nam);
> + } else if (!strcmp(argv[2], "unset")) {
> + gpiounset(pin, nm);
> + } else {
> + value = strtonum(argv[2], INT_MIN, INT_MAX, &errstr);
> + if (errstr) {
> + if (!strcmp(argv[2], "on"))
> + value = GPIO_PIN_HIGH;
> + else if (!strcmp(argv[2], "off"))
> + value = GPIO_PIN_LOW;
> + else if (!strcmp(argv[2], "toggle"))
> + value = 2;
> + else
> + errx(EXIT_FAILURE, "%s: invalid value",argv[2]);
> + }
> + gpiowrite(pin, nm, value);
> }
> +
> return EXIT_SUCCESS;
> }
>
> @@ -214,12 +183,12 @@ getinfo(void)
> }
>
> static void
> -gpioread(int pin, char *gp_name)
> +gpioread(int pin, const char *gp_name)
> {
> struct gpio_req req;
>
> memset(&req, 0, sizeof(req));
> - if (gp_name != NULL)
> + if (gp_name)
> strlcpy(req.gp_name, gp_name, sizeof(req.gp_name));
> else
> req.gp_pin = pin;
> @@ -240,7 +209,7 @@ gpioread(int pin, char *gp_name)
> }
>
> static void
> -gpiowrite(int pin, char *gp_name, int value)
> +gpiowrite(int pin, const char *gp_name, int value)
> {
> struct gpio_req req;
>
> @@ -248,7 +217,7 @@ gpiowrite(int pin, char *gp_name, int value)
> errx(EXIT_FAILURE, "%d: invalid value", value);
>
> memset(&req, 0, sizeof(req));
> - if (gp_name != NULL)
> + if (gp_name)
> strlcpy(req.gp_name, gp_name, sizeof(req.gp_name));
> else
> req.gp_pin = pin;
> @@ -257,10 +226,8 @@ gpiowrite(int pin, char *gp_name, int value)
> req.gp_value = value;
> if (ioctl(devfd, GPIOWRITE, &req) == -1)
> err(EXIT_FAILURE, "GPIOWRITE");
> - } else {
> - if (ioctl(devfd, GPIOTOGGLE, &req) == -1)
> - err(EXIT_FAILURE, "GPIOTOGGLE");
> - }
> + } else if (ioctl(devfd, GPIOTOGGLE, &req) == -1)
> + err(EXIT_FAILURE, "GPIOTOGGLE");
>
> if (state)
> printf("%d\n", value < 2 ? value : 1 - req.gp_value);
> @@ -277,19 +244,19 @@ gpiowrite(int pin, char *gp_name, int value)
> }
>
I don't see an advantage of just rearranging the code.
> static void
> -gpioset(int pin, char *name, int fl, char *alias)
> +gpioset(int pin, const char *name, int fl, const char *alias)
> {
> struct gpio_set set;
> const struct bitstr *bs;
>
> memset(&set, 0, sizeof(set));
> - if (name != NULL)
> + if (name)
technically correct, but I prefer the expressivenes of the original
statement.
> strlcpy(set.gp_name, name, sizeof(set.gp_name));
> else
> set.gp_pin = pin;
> set.gp_flags = fl;
>
> - if (alias != NULL)
> + if (alias)
> strlcpy(set.gp_name2, alias, sizeof(set.gp_name2));
>
> if (ioctl(devfd, GPIOSET, &set) == -1)
> @@ -298,20 +265,20 @@ gpioset(int pin, char *name, int fl, char *alias)
> if (quiet)
> return;
>
> - if (name != NULL)
> + if (name)
> printf("pin %s: caps:", name);
> else
> printf("pin %d: caps:", pin);
> - for (bs = pinflags; bs->string != NULL; bs++)
> + for (bs = pinflags; bs->string; bs++)
> if (set.gp_caps & bs->mask)
> printf(" %s", bs->string);
> printf(", flags:");
> - for (bs = pinflags; bs->string != NULL; bs++)
> + for (bs = pinflags; bs->string; bs++)
> if (set.gp_flags & bs->mask)
> printf(" %s", bs->string);
> if (fl > 0) {
> printf(" ->");
> - for (bs = pinflags; bs->string != NULL; bs++)
> + for (bs = pinflags; bs->string; bs++)
> if (fl & bs->mask)
> printf(" %s", bs->string);
> }
> @@ -319,12 +286,12 @@ gpioset(int pin, char *name, int fl, char *alias)
> }
>
> static void
> -gpiounset(int pin, char *name)
> +gpiounset(int pin, const char *name)
> {
> struct gpio_set set;
>
> memset(&set, 0, sizeof(set));
> - if (name != NULL)
> + if (name)
> strlcpy(set.gp_name, name, sizeof(set.gp_name));
> else
> set.gp_pin = pin;
> @@ -333,16 +300,45 @@ gpiounset(int pin, char *name)
> err(EXIT_FAILURE, "GPIOUNSET");
> }
>
> +static unsigned
> +get_uint_or_die(const char *str, const char *name)
> +{
> + int oerrno;
> + char *ep;
> +
> + long lval = strtol(str, &ep, 0);
> + if (!*str || *ep)
> + errx(EXIT_FAILURE, "invalid %s (not a number)", name);
> +
> + oerrno = errno, errno = 0;
> +
> + if ((errno == ERANGE && (lval == LONG_MAX || lval == LONG_MIN))
> + || lval < 0 || (unsigned long)lval > UINT_MAX)
> + errx(EXIT_FAILURE, "%s out of range", name);
> +
> + errno = oerrno;
> +
> + return (unsigned)lval;
> +}
> +
> static void
> -devattach(char *dvname, int offset, uint32_t mask, uint32_t flags)
> +devattach(const char *driver, const char *offset,
> + const char *mask, const char *flags)
> {
> - struct gpio_attach attach;
> + const char *errstr;
> + struct gpio_attach attach = { .ga_flags = 0 };
> +
> + attach.ga_offset = strtonum(offset, 0, INT_MAX, &errstr);
> + if (errstr)
> + errx(EXIT_FAILURE, "offset is %s: %s", errstr, offset);
> +
> + attach.ga_mask = get_uint_or_die(mask, "mask");
> +
> + if (flags)
> + attach.ga_flags = get_uint_or_die(flags, "flags");
> +
> + strlcpy(attach.ga_dvname, driver, sizeof(attach.ga_dvname));
>
> - memset(&attach, 0, sizeof(attach));
> - strlcpy(attach.ga_dvname, dvname, sizeof(attach.ga_dvname));
> - attach.ga_offset = offset;
> - attach.ga_mask = mask;
> - attach.ga_flags = flags;
> if (ioctl(devfd, GPIOATTACH, &attach) == -1)
> err(EXIT_FAILURE, "GPIOATTACH");
> }
> @@ -350,17 +346,14 @@ devattach(char *dvname, int offset, uint32_t mask, uint32_t flags)
> static void
> usage(void)
> {
> - const char *progname;
> -
> - progname = getprogname();
> - fprintf(stderr, "usage: %s [-qs] device [pin] [0 | 1 | 2 | "
> - "on | off | toggle]\n", progname);
> - fprintf(stderr, " %s [-q] device pin set [flags] [name]\n",
> - progname);
> - fprintf(stderr, " %s [-q] device pin unset\n", progname);
> - fprintf(stderr, " %s [-q] device attach device offset mask "
> - "[flag]\n",
> - progname);
> + const char *pn = getprogname();
> +
> + #define U(...) fprintf(stderr, __VA_ARGS__)
> + U("usage: %s [-qs] device [pin] [0 | 1 | 2 | on | off | toggle]\n", pn);
> + U(" %s [-q] device pin set [flags] [name]\n", pn);
> + U(" %s [-q] device pin unset\n", pn);
> + U(" %s [-q] device attach device offset mask [flag]\n", pn);
> + #undef U
This is ugly to say the lease, please, no, no, no...
In conclusion, I don't like your patch, and since same/similar code is
used in other BSDs, I think we should not apply it.
>
> exit(EXIT_FAILURE);
> }
>
Home |
Main Index |
Thread Index |
Old Index