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(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 = (char **)realloc(color_ansi, max_color_ansi * sizeof(char *)); 106 } 107 color_ansi[num_color_ansi] = strdup(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 = (char **)malloc(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 = (color_entry *)malloc(sizeof(color_entry)); 147 len = min - p; 148 ce->tag = (char *)malloc(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(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 = (color_entry **)malloc(totaltags * sizeof(color_entry *)); 203 bytag_names = (char **)malloc(totaltags * sizeof(char *)); 204 } 205 206 /* if we dont have enough room then reallocate */ 207 if (tagcnt >= totaltags) 208 { 209 totaltags *= 2; 210 bytag = (color_entry **)realloc(bytag, totaltags * sizeof(color_entry *)); 211 bytag_names = (char **)realloc(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] = strdup(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 void 338 color_debug(FILE *f) 339 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 363 int 364 color_activate(int i) 365 366 { 367 if (i == -1) 368 { 369 color_off = !color_off; 370 } 371 else 372 { 373 color_off = !i; 374 } 375 return color_off; 376 } 377