1 /*
2 * Copyright (c) 1984 through 2008, William LeFebvre
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 *
11 * * Redistributions in binary form must reproduce the above
12 * copyright notice, this list of conditions and the following disclaimer
13 * in the documentation and/or other materials provided with the
14 * distribution.
15 *
16 * * Neither the name of William LeFebvre nor the names of other
17 * contributors may be used to endorse or promote products derived from
18 * this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32
33 /*
34 * Top users/processes display for Unix
35 * Version 3
36 */
37
38 /*
39 * This file handles color definitions and access for augmenting
40 * the output with ansi color sequences.
41 *
42 * The definition of a color setting is as follows, separated by
43 * colons:
44 *
45 * tag=minimum,maximum#code
46 *
47 * "tag" is the name of the value to display with color.
48 *
49 * "minimum" and "maximum" are positive integer values defining a range:
50 * when the value is within this range it will be shown with the
51 * specified color. A missing value indicates that no check should be
52 * made (i.e.: ",25" is n <= 25; "25,50" is 25 <= n <= 50; and "50,"
53 * is 50 <= n).
54 *
55 * "code" is the ansi sequence that defines the color to use with the
56 * escape sequence "[m". Semi-colons are allowed in this string to
57 * combine attributes.
58 */
59
60 #include "os.h"
61 #include "display.h"
62 #include "message.h"
63 #include "color.h"
64 #include "utils.h"
65
66 typedef struct color_entry {
67 char *tag;
68 int min;
69 int max;
70 char color;
71 struct color_entry *next;
72 struct color_entry *tagnext;
73 } color_entry;
74
75 static color_entry *entries = NULL;
76
77 static color_entry **bytag = NULL;
78 static char **bytag_names = NULL;
79 static int totaltags = 0;
80 static int tagcnt = 0;
81 static int color_off = 0;
82
83 static char **color_ansi = NULL;
84 static int num_color_ansi = 0;
85 static int max_color_ansi = 0;
86
87 static int
color_slot(const char * str)88 color_slot(const char *str)
89
90 {
91 int i;
92
93 for (i = 0; i < num_color_ansi; i++)
94 {
95 if (strcmp(color_ansi[i], str) == 0)
96 {
97 return i;
98 }
99 }
100
101 /* need a new slot */
102 if (num_color_ansi >= max_color_ansi)
103 {
104 max_color_ansi += COLOR_ANSI_SLOTS;
105 color_ansi = erealloc(color_ansi, max_color_ansi * sizeof(char *));
106 }
107 color_ansi[num_color_ansi] = estrdup(str);
108 return num_color_ansi++;
109 }
110
111 /*
112 * int color_env_parse(char *env)
113 *
114 * Parse a color specification "env" (such as one found in the environment) and
115 * add them to the list of entries. Always returns 0. Should only be called
116 * once.
117 */
118
119 int
color_env_parse(char * env)120 color_env_parse(char *env)
121
122 {
123 char *p;
124 char *min;
125 char *max;
126 char *str;
127 int len;
128 color_entry *ce;
129
130 /* initialization */
131 color_ansi = emalloc(COLOR_ANSI_SLOTS * sizeof(char *));
132 max_color_ansi = COLOR_ANSI_SLOTS;
133
134 /* color slot 0 is always "0" */
135 color_slot("0");
136
137 if (env != NULL)
138 {
139 p = strtok(env, ":");
140 while (p != NULL)
141 {
142 if ((min = strchr(p, '=')) != NULL &&
143 (max = strchr(min, ',')) != NULL &&
144 (str = strchr(max, '#')) != NULL)
145 {
146 ce = emalloc(sizeof(color_entry));
147 len = min - p;
148 ce->tag = emalloc(len + 1);
149 strncpy(ce->tag, p, len);
150 ce->tag[len] = '\0';
151 ce->min = atoi(++min);
152 ce->max = atoi(++max);
153 ce->color = color_slot(++str);
154 ce->next = entries;
155 entries = ce;
156 }
157 else
158 {
159 if (min != NULL)
160 {
161 len = min - p;
162 }
163 else
164 {
165 len = strlen(p);
166 }
167 message_error(" %.*s: bad color entry", len, p);
168 }
169 p = strtok(NULL, ":");
170 }
171 }
172 return 0;
173 }
174
175 /*
176 * int color_tag(char *tag)
177 *
178 * Declare "tag" as a color tag. Return a tag index to use when testing
179 * a value against the tests for this tag. Should not be called before
180 * color_env_parse.
181 */
182
183 int
color_tag(const char * tag)184 color_tag(const char *tag)
185
186 {
187 color_entry *entryp;
188 color_entry *tp;
189
190 /* check for absurd arguments */
191 if (tag == NULL || *tag == '\0')
192 {
193 return -1;
194 }
195
196 dprintf("color_tag(%s)\n", tag);
197
198 /* initial allocation */
199 if (bytag == NULL)
200 {
201 totaltags = 10;
202 bytag = emalloc(totaltags * sizeof(color_entry *));
203 bytag_names = emalloc(totaltags * sizeof(char *));
204 }
205
206 /* if we dont have enough room then reallocate */
207 if (tagcnt >= totaltags)
208 {
209 totaltags *= 2;
210 bytag = erealloc(bytag, totaltags * sizeof(color_entry *));
211 bytag_names = erealloc(bytag_names, totaltags * sizeof(char *));
212 }
213
214 /* initialize scan */
215 entryp = entries;
216 tp = NULL;
217
218 /* look for tag in the list of entries */
219 while (entryp != NULL)
220 {
221 if (strcmp(entryp->tag, tag) == 0)
222 {
223 entryp->tagnext = tp;
224 tp = entryp;
225 }
226 entryp = entryp->next;
227 }
228
229 /* we track names in the array bytag */
230 bytag[tagcnt] = tp;
231 bytag_names[tagcnt] = estrdup(tag);
232
233 /* return this index number as a reference */
234 dprintf("color_tag: returns %d\n", tagcnt);
235 return (tagcnt++);
236 }
237
238 /*
239 * int color_test(int tagidx, int value)
240 *
241 * Test "value" against tests for tag "tagidx", a number previously returned
242 * by color_tag. Return the correct color number to use when highlighting.
243 * If there is no match, return 0 (color 0).
244 */
245
246 int
color_test(int tagidx,int value)247 color_test(int tagidx, int value)
248
249 {
250 color_entry *ce;
251
252 /* sanity check */
253 if (tagidx < 0 || tagidx >= tagcnt || color_off)
254 {
255 return 0;
256 }
257
258 ce = bytag[tagidx];
259
260 while (ce != NULL)
261 {
262 if ((!ce->min || ce->min <= value) &&
263 (!ce->max || ce->max >= value))
264 {
265 return ce->color;
266 }
267 ce = ce->tagnext;
268 }
269
270 return 0;
271 }
272
273 /*
274 * char *color_setstr(int color)
275 *
276 * Return ANSI string to set the terminal for color number "color".
277 */
278
279 char *
color_setstr(int color)280 color_setstr(int color)
281
282 {
283 static char v[32];
284
285 v[0] = '\0';
286 if (color >= 0 && color < num_color_ansi)
287 {
288 snprintf(v, sizeof(v), "\033[%sm", color_ansi[color]);
289 }
290 return v;
291 }
292
293 void
color_dump(FILE * f)294 color_dump(FILE *f)
295
296 {
297 color_entry *ep;
298 int i;
299 int col;
300 int len;
301
302 fputs("These color tags are available:", f);
303 col = 81;
304 for (i = 0; i < tagcnt; i++)
305 {
306 len = strlen(bytag_names[i]) + 1;
307 if (len + col > 79)
308 {
309 fputs("\n ", f);
310 col = 2;
311 }
312 fprintf(f, " %s", bytag_names[i]);
313 col += len;
314 }
315
316 fputs("\n\nTop color settings:\n", f);
317
318 for (i = 0; i < tagcnt; i++)
319 {
320 ep = bytag[i];
321 while (ep != NULL)
322 {
323 fprintf(f, " %s (%d-", ep->tag, ep->min);
324 if (ep->max != 0)
325 {
326 fprintf(f, "%d", ep->max);
327 }
328 fprintf(f, "): ansi color %s, %sSample Text",
329 color_ansi[(int)ep->color],
330 color_setstr(ep->color));
331 fprintf(f, "%s\n", color_setstr(0));
332 ep = ep -> tagnext;
333 }
334 }
335 }
336
337 #ifdef notdef
338 void
color_debug(FILE * f)339 color_debug(FILE *f)
340 {
341 color_entry *ep;
342 int i;
343
344 fprintf(f, "color debug dump\n");
345 ep = entries;
346 while (ep != NULL)
347 {
348 fprintf(f, "%s(%d,%d): slot %d, ansi %s, %sSample Text",
349 ep->tag, ep->min, ep->max, ep->color, color_ansi[(int)ep->color],
350 color_setstr(ep->color));
351 fprintf(f, "%s\n", color_setstr(0));
352 ep = ep -> next;
353 }
354
355 fprintf(f, "\ntags:");
356 for (i = 0; i < tagcnt; i++)
357 {
358 fprintf(f, " %s", bytag_names[i]);
359 }
360 fprintf(f, "\n");
361 }
362 #endif
363
364 int
color_activate(int i)365 color_activate(int i)
366
367 {
368 if (i == -1)
369 {
370 color_off = !color_off;
371 }
372 else
373 {
374 color_off = !i;
375 }
376 return color_off;
377 }
378