xref: /dflybsd-src/usr.bin/top/color.c (revision dc4f0af10c302f890123c000480a85f47d731199)
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