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}