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