Home | History | Annotate | Line # | Download | only in dist
      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
     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
    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
    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
    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 *
    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
    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
    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
    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