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:
M | Makefile | | | 16 | ++-------------- |
M | watch.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;
}