1 /* Prints a rainbow in html span tags, using css...
2 *
3 * red (0xF00), orange, yellow (0xFF0),
4 * yellow (0xFF0), green (0x0F0),
5 * green (0x0F0), cyan (0x0FF),
6 * cyan (0x0FF), blue (0x00F),
7 * blue (0x00F), indigo, violet (0xF0F)
8 *
9 * ... repeat.
10 */
11 #include "ex_utils.h"
12
13 #define EX_RAINBOW_USE_256 0 /* use a 256 or a 16 step gradient color change */
14 #define EX_RAINBOW_USE_PUNCT 1 /* color punctuation chars */
15
16 #define EX_RAINBOW_PUNCT_CHARS \
17 "!\"#$%&'()*+,-./:;<=>?[\\]^_`{|}~"
18 #define EX_RAINBOW_ALPHA_CHARS \
19 "ABCDEFGHIJKLMNOPQRSTUVWXYZ" \
20 "abcdefghijklmnopqrstuvwxyz" \
21 "0123456789"
22
23 #if EX_RAINBOW_USE_PUNCT
24 #define EX_RAINBOW_CHARS EX_RAINBOW_ALPHA_CHARS EX_RAINBOW_PUNCT_CHARS
25 #else
26 #define EX_RAINBOW_CHARS EX_RAINBOW_ALPHA_CHARS
27 #endif
28
29 /* states */
30 #define EX_RAINBOW_ST_R2Y 0
31 #define EX_RAINBOW_ST_Y2G 1
32 #define EX_RAINBOW_ST_G2C 2
33 #define EX_RAINBOW_ST_C2B 3
34 #define EX_RAINBOW_ST_B2V 4
35 #define EX_RAINBOW_ST_V2R 5
36
37 static struct
38 {
39 unsigned int r;
40 unsigned int g;
41 unsigned int b;
42 int state;
43 } color = {(EX_RAINBOW_USE_256 ? 0xFF : 0xF), 0, 0, 0};
44
45
ex_rainbow_process(Vstr_base * s1,Vstr_base * s2)46 static void ex_rainbow_process(Vstr_base *s1, Vstr_base *s2)
47 {
48 while (s2->len)
49 {
50 size_t skip = vstr_cspn_cstr_chrs_fwd(s2, 1, s2->len, EX_RAINBOW_CHARS);
51 int hexsz = EX_RAINBOW_USE_256 * 2;
52 unsigned int hexmax = (EX_RAINBOW_USE_256 ? 0xFF : 0xF);
53 unsigned int hexmin = 0;
54
55 vstr_add_vstr(s1, s1->len, s2, 1, skip, VSTR_TYPE_ADD_DEF);
56 vstr_del(s2, 1, skip);
57
58 if (!s2->len)
59 return;
60
61 ASSERT(color.r <= hexmax);
62 ASSERT(color.g <= hexmax);
63 ASSERT(color.b <= hexmax);
64
65 vstr_add_fmt(s1, s1->len,
66 "<span style=\"color: #%0*x%0*x%0*x\">"
67 "${vstr:%p%zu%zu%u}"
68 "</span>",
69 hexsz, color.r, hexsz, color.g, hexsz, color.b,
70 s2, 1, 1, VSTR_TYPE_ADD_DEF);
71
72 if (s1->conf->malloc_bad)
73 errno = ENOMEM, err(EXIT_FAILURE, "adding data");
74
75 vstr_del(s2, 1, 1);
76
77 switch (color.state)
78 {
79 case EX_RAINBOW_ST_R2Y:
80 if (++color.g == hexmax) color.state = EX_RAINBOW_ST_Y2G; break;
81 case EX_RAINBOW_ST_Y2G:
82 if (--color.r == hexmin) color.state = EX_RAINBOW_ST_G2C; break;
83 case EX_RAINBOW_ST_G2C:
84 if (++color.b == hexmax) color.state = EX_RAINBOW_ST_C2B; break;
85 case EX_RAINBOW_ST_C2B:
86 if (--color.g == hexmin) color.state = EX_RAINBOW_ST_B2V; break;
87 case EX_RAINBOW_ST_B2V:
88 if (++color.r == hexmax) color.state = EX_RAINBOW_ST_V2R; break;
89 case EX_RAINBOW_ST_V2R:
90 if (--color.b == hexmin) color.state = EX_RAINBOW_ST_R2Y; break;
91
92 default:
93 ASSERT(FALSE);
94 }
95 }
96 }
97
ex_rainbow_read_fd_write_stdout(Vstr_base * s1,Vstr_base * s2,int fd)98 static void ex_rainbow_read_fd_write_stdout(Vstr_base *s1,
99 Vstr_base *s2, int fd)
100 {
101 while (TRUE)
102 {
103 int io_w_state = IO_OK;
104 int io_r_state = io_get(s2, fd);
105
106 if (io_r_state == IO_EOF)
107 break;
108
109 ex_rainbow_process(s1, s2);
110
111 io_w_state = io_put(s1, 1);
112
113 io_limit(io_r_state, fd, io_w_state, 1, s1);
114 }
115
116 ex_rainbow_process(s1, s2);
117 }
118
main(int argc,char * argv[])119 int main(int argc, char *argv[])
120 {
121 Vstr_base *s2 = NULL;
122 Vstr_base *s1 = ex_init(&s2);
123 int count = 1;
124
125 vstr_cntl_conf(NULL, VSTR_CNTL_CONF_SET_FMT_CHAR_ESC, '$');
126 vstr_sc_fmt_add_all(NULL);
127
128 if (!s1->conf)
129 errno = ENOMEM, err(EXIT_FAILURE, "custom formatters");
130
131 if (count >= argc)
132 {
133 io_fd_set_o_nonblock(STDIN_FILENO);
134 ex_rainbow_read_fd_write_stdout(s1, s2, STDIN_FILENO);
135 }
136
137 while (count < argc)
138 {
139 int fd = io_open(argv[count]);
140
141 ex_rainbow_read_fd_write_stdout(s1, s2, fd);
142
143 if (close(fd) == -1)
144 warn("close(%s)", argv[count]);
145
146 ++count;
147 }
148
149 io_put_all(s1, STDOUT_FILENO);
150
151 exit (ex_exit(s1, s2));
152 }
153