watch

minimalist watch program
git clone git://src.adamsgaard.dk/watch
Log | Files | Refs | LICENSE Back to index

commit aaaa2f8bc15b34aa1d66fe30fd4f86bc6ed4ee79
parent 56fe3ac4a98f0f5a3c401ecbb5f281b9d82d04c8
Author: Anders Damsgaard <anders@adamsgaard.dk>
Date:   Sat, 23 May 2020 22:21:39 +0200

Many improvements and style changes

Diffstat:
MMakefile | 16++--------------
Mwatch.c | 152+++++++++++++++++++++++++++++++++++--------------------------------------------
2 files changed, 69 insertions(+), 99 deletions(-)

diff --git a/Makefile b/Makefile @@ -1,33 +1,21 @@ -CFLAGS = -g -std=c99 -pedantic -Wall LDFLAGS = -lm OBJ = watch.o BIN = watch -PREFIX ?= ~/.local -INSTALL ?= install -STRIP ?= strip - -default: $(BIN) +PREFIX = /usr/local $(BIN): $(OBJ) $(HDR) $(CC) $(LDFLAGS) $(OBJ) -o $@ install: $(BIN) - $(STRIP) $(BIN) $(INSTALL) -m 0755 -d $(DESTDIR)$(PREFIX)/bin $(INSTALL) -m 0755 $(BIN) $(DESTDIR)$(PREFIX)/bin uninstall: rm -f $(DESTDIR)$(PREFIX)/bin/$(BIN) -memtest: $(BIN) - valgrind --error-exitcode=1 --leak-check=full $(BIN) -h - valgrind --error-exitcode=1 --leak-check=full $(BIN) -v - valgrind --error-exitcode=1 --leak-check=full $(BIN) -q -r 2 date - valgrind --error-exitcode=1 --leak-check=full $(BIN) -q -n 2 -r 2 ls - clean: rm -f $(OBJ) rm -f $(BIN) -.PHONY: default install uninstall memtest clean +.PHONY: install uninstall clean diff --git a/watch.c b/watch.c @@ -3,49 +3,46 @@ #include <getopt.h> #include <string.h> #include <unistd.h> +#include <stdarg.h> -#define VERSION "0.1.0" -#define PROGNAME "watch" +#define VERSION "0.2.0" +#define CMD_MAX_LEN 45 -void -usage(int interval) +static int interval = 5; + +static void +usage() { printf("%s: %s [OPTIONS] COMMAND\n" "will repeatedly run COMMAND every %d seconds.\n" "Following OPTIONS are valid:\n" - " -h, --help show this message\n" - " -v, --version show version and license information\n" - " -n, --interval SECONDS set interval between command invocations\n" - " -r, --repeat N repeat for N times and then quit\n" - " -q, --quiet suppress output (stdout) from COMMAND\n" - " -c, --no-clear do not clear screen between COMMAND calls\n" - " -- do not consider any following args as options\n" + " -v show version\n" + " -n SECONDS set interval between command invocations\n" + " -r N repeat for N times and then quit\n" + " -q suppress output (stdout) from COMMAND\n" + " -c do not clear screen between COMMAND calls\n" + " -- do not consider any following args as options\n" , - __func__, PROGNAME, interval); + __func__, getprogname(), interval); } -void -version() +static void +die(const char *errstr,...) { - printf("%s version %s\n" - "Licensed under the GNU Public License, v3+\n" - "Written by Anders Damsgaard, anders@adamsgaard.dk\n", - PROGNAME, VERSION); -} + va_list ap; -void -die(char* error_message) -{ - fprintf(stderr, "%s", error_message); + va_start(ap, errstr); + vfprintf(stderr, errstr, ap); + va_end(ap); exit(1); } -void -run_cmd(int sleeptime, char* command, int quiet, int clearscreen) +static void +run_cmd(int sleeptime, char *command, int quiet, int clearscreen) { if (!quiet) { if (clearscreen) - printf("\e[1;1H\e[2J"); /* clear screen (POSIX) */ + printf("\e[1;1H\e[2J"); /* clear screen (POSIX) */ else puts(""); printf("Every %ds: %s\n\n", sleeptime, command); @@ -57,81 +54,66 @@ run_cmd(int sleeptime, char* command, int quiet, int clearscreen) } int -main(int argc, char* argv[]) +main(int argc, char *argv[]) { int i, opt; - int interval, repeat, quiet, clearscreen; - const char* optstring; - char* command; - - interval = 5; - quiet = 0; - optstring = "hvn:r:qc"; - const struct option longopts[] = { - {"help", no_argument, NULL, 'h'}, - {"version", no_argument, NULL, 'v'}, - {"interval", required_argument, NULL, 'n'}, - {"repeat", required_argument, NULL, 'r'}, - {"quiet", no_argument, NULL, 'q'}, - {"no-clear", no_argument, NULL, 'c'}, - {NULL, 0, NULL, 0} - }; + int repeat = 0, quiet = 0, clearscreen = 1; + char command[CMD_MAX_LEN] = ""; - repeat = 0; - clearscreen = 1; - while ((opt = getopt_long(argc, argv, optstring, longopts, NULL)) != -1) { + while ((opt = getopt(argc, argv, "hvn:r:qc")) != -1) { switch (opt) { - case -1: /* no more arguments */ - case 0: /* long options toggles*/ - break; - case 'h': - usage(interval); - return 0; - case 'v': - version(); - return 0; - case 'n': - interval = atoi(optarg); - break; - case 'r': - repeat = atoi(optarg); - break; - case 'q': - quiet = 1; - break; - case 'c': - clearscreen = 0; - break; - default: - fprintf(stderr, "%s: invalid option -- %c\n", argv[0], opt); - fprintf(stderr, "try `%s --help` for more information\n", - argv[0]); - return -2; + case -1: /* no more arguments */ + case 0: /* long options toggles */ + break; + case 'h': + usage(); + return 0; + break; + case 'v': + die("%s " VERSION "\n", argv[0]); + break; + case 'n': + interval = atoi(optarg); + break; + case 'r': + repeat = atoi(optarg); + break; + case 'q': + quiet = 1; + break; + case 'c': + clearscreen = 0; + break; + default: + fprintf(stderr, "%s: invalid option -- %c\n", argv[0], opt); + fprintf(stderr, "try `%s --help` for more information\n", + argv[0]); + return -2; } } + argc -= optind; + argv += optind; - if (optind == argc) + if (argc < 1) die("error: no COMMAND specified\n"); - if ((command = malloc(512)) != NULL) { - command[0] = '\0'; - strcat(command, "[ -f ~/.profile ] && . ~/.profile "); - for (i=optind; i<argc; ++i) { - strcat(command, argv[i]); - if (i < argc-1) - strcat(command, " "); - } - } else { - die("command malloc failed"); + strcat(command, "[ -f ~/.profile ] && . ~/.profile; "); + for (i = 0; i < argc; ++i) { + if (strlen(command) + strlen(argv[i]) + + (i > 0 && i < argc - 1 ? 1 : 0) >= CMD_MAX_LEN) + die("error: command length exceeded\n"); + + strcat(command, argv[i]); + if (i > 0 && i < argc - 1) + strcat(command, " "); } if (repeat > 0) { - for (i=0; i<repeat; ++i) + for (i = 0; i < repeat; ++i) run_cmd(interval, command, quiet, clearscreen); } else { for (;;) run_cmd(interval, command, quiet, clearscreen); } - free(command); return 0; }