-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathunansi.c
More file actions
131 lines (119 loc) · 2.91 KB
/
unansi.c
File metadata and controls
131 lines (119 loc) · 2.91 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
#include <ctype.h>
#include <errno.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#ifdef _WIN32
# define WIN32_LEAN_AND_MEAN
# include <windows.h>
#else
# include <unistd.h>
#endif
#define HALF_BUF_SIZE (4096 * 4)
#define BUF_SIZE (HALF_BUF_SIZE * 2)
#if defined(__GNUC__) || defined(__clang__)
# define UNLIKELY(x) (__builtin_expect(!!(x),false))
# define LIKELY(x) (__builtin_expect(!!(x),true))
#else
# define UNLIKELY(x) (x)
# define LIKELY(x) (x)
#endif
#if defined(__GNUC__) && !defined(__clang__)
# define fwrite fwrite_unlocked
# define fflush fflush_unlocked
#endif
#if defined(_MSC_VER)
// Only used in `write` calls
# define ssize_t int
#endif
struct state {
size_t offset;
size_t amt;
bool dirty;
char buffer[BUF_SIZE];
int stdin_fd;
int stdout_fd;
};
static inline void
fill_buffer(struct state *restrict state) {
state->offset = 0;
state->amt = read(state->stdin_fd, state->buffer, BUF_SIZE);
if (UNLIKELY(state->amt == 0)) {
exit(0);
}
}
static inline void
maybe_flush(struct state *restrict state) {
if (LIKELY(state->dirty)) {
fflush(stdout);
state->dirty = false;
}
}
static inline void
write_out(struct state *restrict state, size_t start) {
if (LIKELY(state->offset - start < HALF_BUF_SIZE)) {
fwrite(&state->buffer[start], 1, state->offset - start, stdout);
state->dirty = true;
} else {
// This branch avoids the excess buffering of using stdout as a
// FILE*, generally in the cases where there's lots of input with
// no ANSI codes.
maybe_flush(state);
size_t written = 0;
size_t amt = state->offset - start;
do {
ssize_t res = write(state->stdout_fd, &state->buffer[start], amt);
if (UNLIKELY(res < 0)) {
if (errno == EINTR) {
continue;
}
perror("Can't write data out");
exit(1);
} else {
written += res;
}
} while (written < amt);
}
}
int main(void) {
struct state state = {
.stdin_fd = fileno(stdin),
.stdout_fd = fileno(stdout),
.offset = 0,
.amt = 0,
};
start_normal_chunk:
fill_buffer(&state);
start_normal:
{
size_t start = state.offset;
for (; state.offset < state.amt; state.offset++) {
char c = state.buffer[state.offset];
switch (c) {
case 0x07: // bel
case 0x08: // backspace
case 0x0c: // form feed
case 0x7f: // delete
write_out(&state, start);
goto start_normal;
case 0x1b: // escape
write_out(&state, start);
goto start_escape;
default:
continue;
}
}
write_out(&state, start);
goto start_normal_chunk;
}
start_escape_chunk:
fill_buffer(&state);
start_escape:
for (; state.offset < state.amt; state.offset++) {
if (UNLIKELY(isalpha(state.buffer[state.offset]))) {
state.offset++;
goto start_normal;
}
}
goto start_escape_chunk;
}