1 #define _POSIX_C_SOURCE 200809L
8 void die(const char *message
) {
9 fputs(message
, stderr
);
14 void die_err(const char *message
) {
19 char *encode_time(time_t t
) {
22 const size_t size
= 20;
23 char *out
= (char *)malloc(size
);
24 if (strftime(out
, size
, "%Y %m %d %H %M %S", &tm
) != size
- 1)
25 die("Couldn't format time");
37 const time_t NULL_TIME
= (time_t)-1;
39 static time_range_t
make_time_range(time_t t
) { return (time_range_t
){t
, t
}; }
41 static void extend_time_range(time_range_t
*r
, time_t t
) { r
->end
= t
; }
43 static char *read_line() {
45 int scanf_ret
= scanf("%m[^\n]", &line
);
46 if (scanf_ret
== EOF
&& ferror(stdin
))
47 die_err("Error reading");
48 int newline
= getchar();
49 if (newline
!= EOF
&& newline
!= (int)'\n')
50 die("Expected newline");
51 if (scanf_ret
== 0 && newline
== (int)'\n')
56 static void format_time(conf_t
*conf
, char *buf
, size_t size
, time_t *t
) {
57 struct tm
*tm
= localtime(t
);
59 die_err("Couldn't unpack time");
60 if (strftime(buf
, size
, conf
->time_format
, tm
) == 0)
61 die_err("Couldn't format time");
64 static void write_line(conf_t
*conf
, time_range_t
*range
, char *line
) {
67 if (conf
->time_format
) {
68 const size_t MAX_TIMESTAMP_LENGTH
= 1024;
69 char a
[MAX_TIMESTAMP_LENGTH
];
70 char b
[MAX_TIMESTAMP_LENGTH
];
71 format_time(conf
, a
, MAX_TIMESTAMP_LENGTH
, &range
->start
);
72 format_time(conf
, b
, MAX_TIMESTAMP_LENGTH
, &range
->end
);
73 if (printf("%s %s %s\n", a
, b
, line
) < 0)
74 die("Couldn't write");
76 if (printf("%ld %ld %s\n", range
->start
, range
->end
, line
) < 0)
77 die("Couldn't write");
79 if (fflush(stdout
) == EOF
)
80 die_err("Couldn't flush");
83 static int same(char *a
, char *b
) { return a
&& b
&& strcmp(a
, b
) == 0; }
85 static void uniqt(conf_t
*conf
) {
86 char *current_line
= NULL
;
87 time_range_t current_time_range
= make_time_range(NULL_TIME
);
89 char *new_line
= read_line();
92 time_t now
= time(NULL
);
93 if (same(current_line
, new_line
)) {
95 extend_time_range(¤t_time_range
, now
);
97 write_line(conf
, ¤t_time_range
, current_line
);
99 current_line
= new_line
;
100 current_time_range
= make_time_range(now
);
103 write_line(conf
, ¤t_time_range
, current_line
);
107 void usage() { die("usage: uniqt [-f time_format]"); }
109 conf_t
parse_command_line(int argc
, char *argv
[]) {
111 conf
.time_format
= NULL
;
113 for (int i
= 1; i
< argc
; i
++) {
114 if (strcmp(argv
[i
], "-f") == 0) {
116 die("-f requires an argument");
118 conf
.time_format
= argv
[i
];
126 int main(int argc
, char *argv
[]) {
127 conf_t conf
= parse_command_line(argc
, argv
);