summaryrefslogtreecommitdiffstats
path: root/lib/color.c
blob: cd0f9f7509b5f73598ae794c0c6bfec16d49a254 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
/* SPDX-License-Identifier: GPL-2.0 */
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <linux/if.h>

#include "color.h"
#include "utils.h"

static void set_color_palette(void);

enum color {
	C_RED,
	C_GREEN,
	C_YELLOW,
	C_BLUE,
	C_MAGENTA,
	C_CYAN,
	C_WHITE,
	C_BOLD_RED,
	C_BOLD_GREEN,
	C_BOLD_YELLOW,
	C_BOLD_BLUE,
	C_BOLD_MAGENTA,
	C_BOLD_CYAN,
	C_BOLD_WHITE,
	C_CLEAR
};

static const char * const color_codes[] = {
	"\e[31m",
	"\e[32m",
	"\e[33m",
	"\e[34m",
	"\e[35m",
	"\e[36m",
	"\e[37m",
	"\e[1;31m",
	"\e[1;32m",
	"\e[1;33m",
	"\e[1;34m",
	"\e[1;35m",
	"\e[1;36m",
	"\e[1;37m",
	"\e[0m",
	NULL,
};

/* light background */
static enum color attr_colors_light[] = {
	C_CYAN,
	C_YELLOW,
	C_MAGENTA,
	C_BLUE,
	C_GREEN,
	C_RED,
	C_CLEAR,
};

/* dark background */
static enum color attr_colors_dark[] = {
	C_BOLD_CYAN,
	C_BOLD_YELLOW,
	C_BOLD_MAGENTA,
	C_BOLD_BLUE,
	C_BOLD_GREEN,
	C_BOLD_RED,
	C_CLEAR
};

static int is_dark_bg;
static int color_is_enabled;

static void enable_color(void)
{
	color_is_enabled = 1;
	set_color_palette();
}

bool check_enable_color(int color, int json)
{
	if (json || color == COLOR_OPT_NEVER)
		return false;

	if (color == COLOR_OPT_ALWAYS || isatty(fileno(stdout))) {
		enable_color();
		return true;
	}
	return false;
}

bool matches_color(const char *arg, int *val)
{
	char *dup, *p;

	if (!val)
		return false;

	dup = strdupa(arg);
	p = strchrnul(dup, '=');
	if (*p)
		*(p++) = '\0';

	if (matches(dup, "-color"))
		return false;

	if (*p == '\0' || !strcmp(p, "always"))
		*val = COLOR_OPT_ALWAYS;
	else if (!strcmp(p, "auto"))
		*val = COLOR_OPT_AUTO;
	else if (!strcmp(p, "never"))
		*val = COLOR_OPT_NEVER;
	else
		return false;
	return true;
}

static void set_color_palette(void)
{
	char *p = getenv("COLORFGBG");

	/*
	 * COLORFGBG environment variable usually contains either two or three
	 * values separated by semicolons; we want the last value in either case.
	 * If this value is 0-6 or 8, background is dark.
	 */
	if (p && (p = strrchr(p, ';')) != NULL
		&& ((p[1] >= '0' && p[1] <= '6') || p[1] == '8')
		&& p[2] == '\0')
		is_dark_bg = 1;
}

__attribute__((format(printf, 3, 4)))
int color_fprintf(FILE *fp, enum color_attr attr, const char *fmt, ...)
{
	int ret = 0;
	va_list args;

	if (fmt == NULL)
		return 0;

	va_start(args, fmt);

	if (!color_is_enabled || attr == COLOR_NONE) {
		ret = vfprintf(fp, fmt, args);
		goto end;
	}

	ret += fprintf(fp, "%s", color_codes[is_dark_bg ?
		attr_colors_dark[attr] : attr_colors_light[attr]]);

	ret += vfprintf(fp, fmt, args);
	ret += fprintf(fp, "%s", color_codes[C_CLEAR]);

end:
	va_end(args);
	return ret;
}

enum color_attr ifa_family_color(__u8 ifa_family)
{
	switch (ifa_family) {
	case AF_INET:
		return COLOR_INET;
	case AF_INET6:
		return COLOR_INET6;
	default:
		return COLOR_NONE;
	}
}

enum color_attr oper_state_color(__u8 state)
{
	switch (state) {
	case IF_OPER_UP:
		return COLOR_OPERSTATE_UP;
	case IF_OPER_DOWN:
		return COLOR_OPERSTATE_DOWN;
	default:
		return COLOR_NONE;
	}
}