netdev: Fix potential deadlock.
[cascardo/ovs.git] / lib / colors.c
1 /*
2  * Copyright (c) 2016 6WIND S.A.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at:
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 /* Handle color setup for output. */
18
19 #include <config.h>
20
21 #include "colors.h"
22
23 #include <stdlib.h>
24 #include <string.h>
25
26 #include "util.h"
27
28 struct color_key {
29     const char *name;
30     char **var_ptr;
31 };
32
33 /* Returns a pointer to the variable containing a given color. */
34 static char **get_color(const struct color_key color_dic[], const char * name);
35
36 /* Extract user-defined colors from OVS_COLORS environment variable. */
37 static void colors_parse_from_env(const struct color_key color_dic[]);
38
39 /* Global holder for colors. Declared in header file. */
40 struct colors colors = { "", "", "", "", "", "", "", "" };
41
42 static char **
43 get_color(const struct color_key color_dic[], const char *name)
44 {
45     const struct color_key *color;
46     for (color = color_dic; color->name; color++) {
47         if (!strcmp(color->name, name)) {
48             return color->var_ptr;
49         }
50     }
51     return NULL;
52 }
53
54 void
55 colors_init(bool enable_color)
56 {
57     /* If colored output is not enabled, just keep empty strings for color
58      * markers, including end marker.
59      */
60     if (!enable_color) {
61         return;
62     }
63
64     /* Color IDs to use in OVS_COLORS environment variable to overwrite
65      * defaults with custom colors.
66      */
67     const struct color_key color_dic[] = {
68         { "ac", &colors.actions },
69         { "dr", &colors.drop },
70         { "le", &colors.learn },
71         { "pm", &colors.param },
72         { "pr", &colors.paren },
73         { "sp", &colors.special },
74         { "vl", &colors.value },
75         { NULL, NULL }
76     };
77
78     /* Actual color to use. First we define default values. */
79     colors.actions = "\33[1;31m\33[K";  /* bold red */
80     colors.drop    = "\33[34m\33[K";    /* blue */
81     colors.learn   = "\33[31m\33[K";    /* red */
82     colors.param   = "\33[36m\33[K";    /* cyan */
83     colors.paren   = "\33[35m\33[K";    /* magenta */
84     colors.special = "\33[33m\33[K";    /* yellow */
85     colors.value   = "\33[32m\33[K";    /* green */
86     colors.end     = "\33[m\33[K";      /* end marker */
87
88     /* Now, overwrite with user-defined color markers. */
89     colors_parse_from_env(color_dic);
90 }
91
92 /* Colorized output: get user-defined colors from OVS_COLORS environment
93  * variable. This must be a string of the form:
94  *     ac=01;31:r=34:le=:pm=02;32:pr=01;30
95  * (see color_dic[] in colors_init() function for all color names)
96  * If a color is missing from this string, default value is used instead.
97  * If a color name is assigned an empty or incorrect value (i.e. something
98  * containing characters other than decimals and ';'), fields using this color
99  * will not be highlighted.
100  * If a color is assigned more than once, the last (rightmost) value appearing
101  * in the string is kept.
102  * Unknown color names are ignored so as to ensure forward compatibility.
103  * (Feeling adventurous? Try combining markers: "ac=1;3;5;7;38;2;30;150;100".)
104  */
105 static void
106 colors_parse_from_env(const struct color_key color_dic[])
107 {
108     const char *color_str = getenv("OVS_COLORS");
109     if (color_str == NULL || *color_str == '\0') {
110         return;
111     }
112
113     /* Loop on tokens: they are separated by columns ':' */
114     char *s = xstrdup(color_str);
115     for (char *token = strsep(&s, ":");
116          token != NULL;
117          token = strsep(&s, ":")) {
118         char *name = strsep(&token, "=");
119         for (char *ptr = token; ptr != NULL && *ptr != '\0'; ptr++) {
120             /* We accept only decimals and ';' for color marker. */
121             if (*ptr == ';' || (*ptr >= '0' && *ptr <= '9')) {
122                 continue;
123             }
124             name = NULL;
125             break;
126         }
127         if (name != NULL) {
128             /* We found a name and marker contains only decimals and ';'.
129              * Try to get a pointer to associated color variable. */
130             char **color_var_ptr = get_color(color_dic, name);
131             /* If we know that color, update its value. */
132             if (color_var_ptr != NULL) {
133                 *color_var_ptr = xasprintf("\33[%sm\33[K", token);
134             }
135         }
136     }
137     free(s);
138 }