URI:
       tMany improvements and style changes - watch - minimalist watch program
  HTML git clone git://src.adamsgaard.dk/watch
   DIR Log
   DIR Files
   DIR Refs
   DIR LICENSE
       ---
   DIR commit aaaa2f8bc15b34aa1d66fe30fd4f86bc6ed4ee79
   DIR parent 56fe3ac4a98f0f5a3c401ecbb5f281b9d82d04c8
  HTML 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(-)
       ---
   DIR diff --git a/Makefile b/Makefile
       t@@ -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
   DIR diff --git a/watch.c b/watch.c
       t@@ -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);
       t@@ -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;
        }