xref: /freebsd/contrib/wireguard-tools/terminal.c (revision e6bfd18d21b225af6a0ed67ceeaf1293b7b9eba5)
1 // SPDX-License-Identifier: GPL-2.0 OR MIT
2 /*
3  * Copyright (C) 2015-2020 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
4  */
5 
6 #include <stdarg.h>
7 #include <stddef.h>
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <stdbool.h>
12 #include <unistd.h>
13 #include "ctype.h"
14 #include "terminal.h"
15 
16 static bool color_mode(void)
17 {
18 	static int mode = -1;
19 	const char *var;
20 
21 	if (mode != -1)
22 		return mode;
23 	var = getenv("WG_COLOR_MODE");
24 	if (var && !strcmp(var, "always"))
25 		mode = true;
26 	else if (var && !strcmp(var, "never"))
27 		mode = false;
28 	else
29 		mode = isatty(fileno(stdout));
30 	return mode;
31 }
32 
33 static void filter_ansi(const char *fmt, va_list args)
34 {
35 	char *str = NULL;
36 	size_t len, i, j;
37 
38 	if (color_mode()) {
39 		vfprintf(stdout, fmt, args);
40 		return;
41 	}
42 
43 	len = vasprintf(&str, fmt, args);
44 
45 	if (len >= 2) {
46 		for (i = 0; i < len - 2; ++i) {
47 			if (str[i] == '\x1b' && str[i + 1] == '[') {
48 				str[i] = str[i + 1] = '\0';
49 				for (j = i + 2; j < len; ++j) {
50 					if (char_is_alpha(str[j]))
51 						break;
52 					str[j] = '\0';
53 				}
54 				str[j] = '\0';
55 			}
56 		}
57 	}
58 	for (i = 0; i < len; i = j) {
59 		fputs(&str[i], stdout);
60 		for (j = i + strlen(&str[i]); j < len; ++j) {
61 			if (str[j] != '\0')
62 				break;
63 		}
64 	}
65 
66 	free(str);
67 }
68 
69 void terminal_printf(const char *fmt, ...)
70 {
71 	va_list args;
72 
73 	va_start(args, fmt);
74 	filter_ansi(fmt, args);
75 	va_end(args);
76 }
77