Shift X2 status from legacy to archived
[khatus.git] / x5 / khatus.c
index 4626729..5407acd 100644 (file)
@@ -5,6 +5,7 @@
 #include <ctype.h>
 #include <errno.h>
 #include <fcntl.h>
+#include <signal.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -28,7 +29,8 @@
 static const char errmsg[] = ERRMSG;
 static const int  errlen   = sizeof(ERRMSG) - 1;
 
-char *argv0;
+char *argv0 = NULL;
+int running = 1;
 
 /* TODO: Convert slot list to slot array. */
 typedef struct Slot Slot;
@@ -48,6 +50,7 @@ typedef struct Config Config;
 struct Config {
        double interval;
        char * separator;
+       char   expiry_character;
        Slot * slots;
        int    slot_count;
        int    buf_width;
@@ -139,7 +142,9 @@ slot_log(Slot *s)
 void
 slots_log(Slot *head)
 {
-       for (Slot *s = head; s; s = s->next) {
+       Slot *s = head;
+
+       for (; s; s = s->next) {
                slot_log(s);
        }
 }
@@ -173,14 +178,34 @@ slots_assert_fifos_exist(Slot *s)
 }
 
 void
-slot_expire(Slot *s, struct timespec t, char *buf)
+slot_close(Slot *s)
+{
+       close(s->in_fd);
+       s->in_fd        = -1;
+       s->out_pos_cur  = s->out_pos_lo;
+}
+
+void
+slots_close(Slot *s)
+{
+       for (; s; s = s->next)
+               if (s->in_fd > -1)
+                       slot_close(s);
+}
+
+
+void
+slot_expire(Slot *s, struct timespec t, char expiry_character, char *buf)
 {
        struct timespec td;
 
        timespecsub(&t, &(s->in_last_read), &td);
        if (timespeccmp(&td, &(s->out_ttl), >=)) {
-               /* TODO: Maybe configurable expiry character. */
-               memset(buf + s->out_pos_lo, '_', s->out_width);
+               memset(
+                   buf + s->out_pos_lo,
+                   expiry_character,
+                   s->out_width
+               );
                khlib_warn("Slot expired: \"%s\"\n", s->in_fifo);
        }
 }
@@ -313,7 +338,7 @@ slots_read(Config *cfg, struct timespec *ti, char *buf)
                switch (errno) {
                case EINTR:
                        khlib_error(
-                           "pselect temp failure: %d, errno: %d, msg: %s\n",
+                           "pselect interrupted: %d, errno: %d, msg: %s\n",
                            ready,
                            errno,
                            strerror(errno)
@@ -367,10 +392,8 @@ slots_read(Config *cfg, struct timespec *ti, char *buf)
                                case END_OF_MESSAGE:
                                case END_OF_FILE:
                                case FAILURE:
-                                       close(s->in_fd);
-                                       s->in_fd        = -1;
+                                       slot_close(s);
                                        s->in_last_read = t;
-                                       s->out_pos_cur  = s->out_pos_lo;
                                        ready--;
                                        break;
                                case RETRY:
@@ -379,7 +402,7 @@ slots_read(Config *cfg, struct timespec *ti, char *buf)
                                        assert(0);
                                }
                        } else {
-                               slot_expire(s, t, buf);
+                               slot_expire(s, t, cfg->expiry_character, buf);
                        }
                }
        } while (ready);
@@ -467,9 +490,12 @@ print_usage()
            "             | -s SEPARATOR\n"
            "             | -x (* Output to X root window *)\n"
            "             | -l LOG_LEVEL\n"
+           "             | -e EXPIRY_CHARACTER\n"
            "  SEPARATOR  = string\n"
            "  INTERVAL   = float  (* (positive) number of seconds *)\n"
            "  LOG_LEVEL  = int  (* %d through %d *)\n"
+           "  EXPIRY_CHARACTER = string  "
+           "(* Character with which to fill the slot upon expiration. *)\n"
            "\n",
            argv0,
            Nothing,
@@ -532,6 +558,15 @@ parse_opts_opt_l(Config *cfg, int argc, char *argv[], int i)
        opts_parse_any(cfg, argc, argv, i);
 }
 
+void
+parse_opts_opt_e(Config *cfg, int argc, char *argv[], int i)
+{
+       if (i >= argc)
+               usage("Option -e parameter is missing.\n");
+       cfg->expiry_character = argv[i++][0];
+       opts_parse_any(cfg, argc, argv, i);
+}
+
 void
 parse_opts_opt(Config *cfg, int argc, char *argv[], int i)
 {
@@ -552,6 +587,10 @@ parse_opts_opt(Config *cfg, int argc, char *argv[], int i)
                /* TODO: Generic set_int */
                parse_opts_opt_l(cfg, argc, argv, ++i);
                break;
+       case 'e':
+               /* TODO: Generic set_str */
+               parse_opts_opt_e(cfg, argc, argv, ++i);
+               break;
        default :
                usage("Option \"%s\" is invalid\n", argv[i]);
        }
@@ -640,7 +679,7 @@ loop(Config *cfg, char *buf, Display *d)
                tc;  /* time interval correction (ti - td) when td < ti */
 
        ti = khlib_timespec_of_float(cfg->interval);
-       for (;;) {
+       while (running) {
                clock_gettime(CLOCK_MONOTONIC, &t0); // FIXME: check errors
                slots_read(cfg, &ti, buf);
                if (cfg->to_x_root) {
@@ -669,12 +708,22 @@ loop(Config *cfg, char *buf, Display *d)
        }
 }
 
+void
+terminate(int s)
+{
+       khlib_debug("terminating due to signal %d\n", s);
+       running = 0;
+}
+
 int
 main(int argc, char *argv[])
 {
+       argv0 = argv[0];
+
        Config cfg = {
                .interval    = 1.0,
                .separator   = "|",
+               .expiry_character = '_',
                .slots       = NULL,
                .slot_count  = 0,
                .buf_width   = 0,
@@ -682,10 +731,13 @@ main(int argc, char *argv[])
        };
        char *buf;
        Display *d = NULL;
+       struct sigaction sa;
 
-       /* TODO: Handle signals */
+       memset(&sa, 0, sizeof(sa));
+       sa.sa_handler = terminate;
+       sigaction(SIGTERM, &sa, NULL);
+       sigaction(SIGINT , &sa, NULL);
 
-       argv0 = argv[0];
        opts_parse(&cfg, argc, argv);
        slots_assert_fifos_exist(cfg.slots);
        config_stretch_for_separators(&cfg);
@@ -693,5 +745,6 @@ main(int argc, char *argv[])
        if (cfg.to_x_root && !(d = XOpenDisplay(NULL)))
                khlib_fatal("XOpenDisplay failed with: %p\n", d);
        loop(&cfg, buf, d);
+       slots_close(cfg.slots);
        return EXIT_SUCCESS;
 }
This page took 0.035915 seconds and 4 git commands to generate.