insomnia

A frontend for the hii IRC client

git clone https://git.8pit.net/insomnia.git

  1#include <err.h>
  2#include <stdio.h>
  3#include <stdlib.h>
  4#include <string.h>
  5#include <signal.h>
  6#include <unistd.h>
  7
  8#include <sys/types.h>
  9
 10static char **lines;
 11static size_t nlines;
 12static int sortdone;
 13
 14enum {
 15	LINESTEP = 16,
 16};
 17
 18static int
 19compar(const void *s1, const void *s2)
 20{
 21	unsigned long long u1, u2;
 22
 23	u1 = strtoull(*(char**)s1, NULL, 10);
 24	u2 = strtoull(*(char**)s2, NULL, 10);
 25
 26	if (u1 > u2) {
 27		return 1;
 28	} else if (u1 < u2) {
 29		return -1;
 30	} else {
 31		return 0;
 32	}
 33}
 34
 35static void
 36sortprint(void)
 37{
 38	size_t i;
 39
 40	qsort(lines, nlines, sizeof(char*), compar);
 41	for (i = 0; i < nlines; i++)
 42		printf("%s", lines[i]);
 43	fflush(stdout);
 44
 45	for (i = 0; i < nlines; i++)
 46		free(lines[i]);
 47	free(lines);
 48	lines = NULL;
 49	nlines = 0;
 50}
 51
 52static void
 53sigalarm(int num)
 54{
 55	(void)num;
 56	sortdone = 1;
 57	sortprint();
 58}
 59
 60static void
 61bufferline(char *line)
 62{
 63	size_t newsiz;
 64
 65	if (nlines && nlines % LINESTEP == 0) {
 66		newsiz = (nlines + LINESTEP) * sizeof(char*);
 67		if (!(lines = realloc(lines, newsiz)))
 68			err(EXIT_FAILURE, "realloc failed");
 69	}
 70
 71	if (!(lines[nlines++] = strdup(line)))
 72		err(EXIT_FAILURE, "strdup failed");
 73}
 74
 75static void
 76sethandler(void)
 77{
 78	struct sigaction act;
 79
 80	act.sa_flags = SA_RESTART;
 81	act.sa_handler = sigalarm;
 82	if (sigemptyset(&act.sa_mask) == -1)
 83		err(EXIT_FAILURE, "sigemptyset failed");
 84	if (sigaction(SIGALRM, &act, NULL))
 85		err(EXIT_FAILURE, "sigaction failed");
 86}
 87
 88static void
 89inloop(sigset_t *blockset)
 90{
 91	static char *line;
 92	static size_t llen;
 93	sigset_t oldset;
 94
 95	while (getline(&line, &llen, stdin) != -1) {
 96		if (sortdone) {
 97			printf("%s", line);
 98			fflush(stdout);
 99			continue;
100		}
101
102		if (sigprocmask(SIG_BLOCK, blockset, &oldset))
103			err(EXIT_FAILURE, "signal blocking failed");
104		bufferline(line);
105		if (sigprocmask(SIG_SETMASK, &oldset, NULL))
106			err(EXIT_FAILURE, "signal unblocking failed");
107	}
108	if (ferror(stdin))
109		err(EXIT_FAILURE, "ferror failed");
110}
111
112int
113main(int argc, char **argv)
114{
115	unsigned int delay;
116	sigset_t blockset;
117
118#ifdef __OpenBSD__
119	if (pledge("stdio", NULL) == -1)
120		err(EXIT_FAILURE, "pledge failed");
121#endif
122
123	if (argc <= 1) {
124		fprintf(stderr, "USAGE: %s DELAY\n", argv[0]);
125		return EXIT_FAILURE;
126	}
127
128	if (!(delay = strtoul(argv[1], NULL, 10)))
129		errx(EXIT_FAILURE, "delay must be a uint greater zero");
130	if (!(lines = malloc(LINESTEP * sizeof(char*))))
131		err(EXIT_FAILURE, "malloc failed");
132
133	sethandler();
134	if (sigemptyset(&blockset) == -1)
135		err(EXIT_FAILURE, "sigemptyset failed");
136	sigaddset(&blockset, SIGALRM);
137	alarm(delay);
138
139	inloop(&blockset);
140	sortprint();
141
142	return EXIT_SUCCESS;
143}