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