1 /*
2 * Copyright (C) 2006-2019, Thomas Maier-Komor
3 *
4 * This is the source code of xjobs.
5 *
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include <errno.h>
21 #include <stdlib.h>
22 #include <strings.h>
23 #include <sys/stat.h>
24 #include <sys/types.h>
25 #include <unistd.h>
26
27 #include "config.h"
28
29 #ifdef HAVE_CURSES_H
30 #include <curses.h>
31 #ifdef __sun // term.h cannot be found on solaris by autoconf
32 #include <term.h> // and requires curses.h as a prerequisite
33 #endif
34 #ifndef HAVE_TERMINFO
35 #define HAVE_TERMINFO
36 #endif
37 #endif
38
39 #define TPARM_VARARGS
40
41 #ifdef HAVE_TERM_H
42 #include <term.h>
43 #ifndef HAVE_TERMINFO
44 #define HAVE_TERMINFO
45 #endif
46 #endif
47
48 #ifdef HAVE_NCURSES_H
49 #include <ncurses.h>
50 #ifndef HAVE_TERMINFO
51 #define HAVE_TERMINFO
52 #endif
53 #endif
54
55 #ifndef ERR
56 #define ERR -1
57 #endif
58
59 #include "colortty.h"
60 #include "log.h"
61 #include "support.h"
62
63 ttymode_t TtyMode = tty_auto;
64
65 int HaveTty = 0;
66
67 color_t
68 ColorStart = cyan,
69 ColorDebug = noattr,
70 ColorInfo = noattr,
71 ColorWarn = yellow,
72 ColorError = red,
73 ColorFail = red,
74 ColorDone = blue,
75 ColorOut = noattr;
76
77 char *PfxStart = "", *PfxDone = "", *PfxFail = "", *PfxWarn = "", *PfxError = ""
78 , *PfxOut = "", *PfxInfo = 0, *PfxDebug = 0;
79
80 const char *TiSave = "", *TiRestore = "", *TiClrEol = "", *TiNoAttr = "",
81 *TiBlack = "", *TiBlue = "", *TiCyan = "", *TiGreen = "", *TiGrey = "",
82 *TiMagenta = "", *TiRed = "", *TiWhite = "", *TiYellow = "";
83
84 unsigned TiClrEolL = 0, TiNoAttrL = 0;
85 int PgPid = 0;
86
87
init_tty_none()88 static void init_tty_none()
89 {
90 TiBlack = "";
91 TiBlue = "";
92 TiCyan = "";
93 TiGreen = "";
94 TiGrey = "";
95 TiMagenta = "";
96 TiRed = "";
97 TiWhite = "";
98 TiYellow = "";
99 TiClrEol = "";
100 TiClrEolL = 0;
101 TiNoAttr = "";
102 TiNoAttrL = 0;
103 TiSave = "";
104 TiRestore = "";
105 }
106
107
init_tty_ansi()108 static void init_tty_ansi()
109 {
110 /* background: black */
111 TiBlack = "\033[30m";
112 TiBlue = "\033[34m";
113 TiCyan = "\033[36m";
114 TiGreen = "\033[32m";
115 TiGrey = "\033[90m";
116 TiMagenta = "\033[35m";
117 TiRed = "\033[31m";
118 TiWhite = "\033[37m";
119 TiYellow = "\033[33m";
120 TiClrEol = "\033[K";
121 TiClrEolL = strlen(TiClrEol);
122 TiNoAttr = "\033[0m";
123 TiNoAttrL = strlen(TiNoAttr);
124 TiSave = "\033[s";
125 TiRestore = "\033[r";
126 }
127
128
colorstr(color_t c)129 const char *colorstr(color_t c)
130 {
131 switch (c) {
132 case black:
133 return TiBlack;
134 case blue:
135 return TiBlue;
136 case cyan:
137 return TiCyan;
138 case green:
139 return TiGreen;
140 case magenta:
141 return TiMagenta;
142 case red:
143 return TiRed;
144 case white:
145 return TiWhite;
146 case yellow:
147 return TiYellow;
148 case noattr:
149 return TiNoAttr;
150 default:
151 abort();
152 }
153 return 0;
154 }
155
156
str2color(const char * str)157 color_t str2color(const char *str)
158 {
159 if (0 == strcasecmp(str,"blue"))
160 return blue;
161 if (0 == strcasecmp(str,"black"))
162 return black;
163 if (0 == strcasecmp(str,"cyan"))
164 return cyan;
165 if (0 == strcasecmp(str,"green"))
166 return green;
167 if (0 == strcasecmp(str,"magenta"))
168 return magenta;
169 if (0 == strcasecmp(str,"red"))
170 return red;
171 if (0 == strcasecmp(str,"white"))
172 return white;
173 if (0 == strcasecmp(str,"yellow"))
174 return yellow;
175 if (0 == strcasecmp(str,"none"))
176 return noattr;
177 if (0 == strcasecmp(str,"default"))
178 return noattr;
179 return invalid_color;
180 }
181
182
init_pager()183 static int init_pager()
184 {
185 char *pager = getenv("PAGER");
186 if (pager == 0) {
187 dbug("pager not set");
188 return 0;
189 }
190 char *pgexe = complete_exe(pager);
191 if (0 == pgexe) {
192 dbug("pager not found");
193 return 0;
194 }
195 info("starting pager %s\n",pgexe);
196 int p[2];
197 if (pipe(p)) {
198 warn("unable to create pipe for pager: %s\n",strerror(errno));
199 return 0;
200 }
201 PgPid = fork();
202 if (PgPid) {
203 if (PgPid == -1) {
204 warn("failed to fork pager: %s\n",strerror(errno));
205 PgPid = 0;
206 return 0;
207 }
208 dup2(p[1],STDERR_FILENO);
209 dup2(p[1],STDOUT_FILENO);
210 close(p[1]);
211 close(p[0]);
212 free(pgexe);
213 } else {
214 dup2(p[0],STDIN_FILENO);
215 close(p[0]);
216 close(p[1]);
217 execl(pgexe,pgexe,NULL);
218 _exit(EXIT_FAILURE);
219 }
220 return 1;
221 }
222
223
init_terminal()224 void init_terminal()
225 {
226 int ispipe = 0;
227 if (1 == isatty(STDOUT_FILENO)) {
228 HaveTty = 1;
229 dbug("stdout is a terminal\n");
230 } else {
231 dbug("stdout is not a terminal\n");
232 struct stat st;
233 int r = fstat(STDOUT_FILENO,&st);
234 if (r == 0) {
235 if (S_ISFIFO(st.st_mode)) {
236 dbug("stdout is a pipe\n");
237 ispipe = 1;
238 }
239 } else {
240 warn("unable to stat output: %s\n",strerror(errno));
241 }
242 }
243 dbug("tty mode %d\n",TtyMode);
244 switch (TtyMode) {
245 case tty_none:
246 case tty_ansi:
247 break;
248 case tty_pipe:
249 if (ispipe == 1)
250 TtyMode = tty_ansi;
251 else if (HaveTty == 1)
252 TtyMode = tty_auto;
253 else
254 TtyMode = tty_none;
255 break;
256 case tty_auto:
257 if (ispipe == 1)
258 TtyMode = tty_ansi;
259 else if (HaveTty == 0)
260 TtyMode = tty_none;
261 break;
262 default:
263 assert(0);
264 }
265 if (HaveTty && init_pager())
266 TtyMode = tty_ansi;
267 if (TtyMode == tty_none) {
268 dbug("tty mode resolved to none - disabling color&status support\n");
269 init_tty_none();
270 return;
271 }
272 if (TtyMode == tty_ansi) {
273 dbug("setting up for ansi terminal\n");
274 init_tty_ansi();
275 }
276 if ((TtyMode == tty_auto) || (TtyMode == tty_pipe)) {
277 #ifdef HAVE_TERMINFO
278 char *ts;
279 int err = 0;
280 if (ERR == setupterm(0,STDOUT_FILENO,&err))
281 return;
282 switch (err) {
283 case 1:
284 dbug("terminal setup ok\n");
285 break;
286 case 0:
287 dbug("no terminal - disabling color\n");
288 break;
289 case -1:
290 default:
291 warn("unable to load terminal database - disabling color\n");
292 }
293 ts = tigetstr("sc");
294 if ((ts != 0) && (ts != (char *)-1))
295 TiSave = ts;
296 ts = tigetstr("rc");
297 if ((ts != 0) && (ts != (char *)-1))
298 TiRestore = ts;
299 ts = tigetstr("el");
300 if ((ts != 0) && (ts != (char *)-1))
301 TiClrEol = ts;
302 TiClrEolL = strlen(TiClrEol);
303 ts = tigetstr("sgr0");
304 if ((ts != 0) && (ts != (char *)-1)) {
305 TiNoAttr = ts;
306 TiNoAttrL = strlen(TiNoAttr);
307 }
308 char *setaf = tigetstr("setaf");
309 char *setf = tigetstr("setf");
310 if (setaf && (setaf != (const char *)-1)) {
311 /* ANSI terminal capabilities */
312 dbug("initializing terminal with ANSI capabilities\n");
313 TiBlack = Strdup(tparm(setaf,0/*BLACK*/));
314 TiRed = Strdup(tparm(setaf,1/*RED*/));
315 TiGreen = Strdup(tparm(setaf,2/*GREEN*/));
316 TiYellow = Strdup(tparm(setaf,3/*YELLOW*/));
317 TiBlue = Strdup(tparm(setaf,4/*BLUE*/));
318 TiMagenta = Strdup(tparm(setaf,5/*MAGENTA*/));
319 TiCyan = Strdup(tparm(setaf,6/*CYAN*/));
320 TiWhite = Strdup(tparm(setaf,7/*WHITE*/));
321 } else if (setf && (setf != (const char *)-1)) {
322 /* NON-ANSI terminal capabilities */
323 dbug("initializing terminal with non-ANSI capabilities\n");
324 TiBlack = Strdup(tparm(setaf,0/*BLACK*/));
325 TiBlue = Strdup(tparm(setf,1/*BLUE*/));
326 TiGreen = Strdup(tparm(setf,2/*GREEN*/));
327 TiCyan = Strdup(tparm(setf,3/*CYAN*/));
328 TiRed = Strdup(tparm(setf,4/*RED*/));
329 TiMagenta = Strdup(tparm(setf,5/*MAGENTA*/));
330 TiYellow = Strdup(tparm(setf,6/*YELLOW*/));
331 TiWhite = Strdup(tparm(setf,7/*WHITE*/));
332 }
333 #else
334 dbug("terminfo is missing - disabling color&status support\n");
335 init_tty_none();
336 #endif
337 }
338
339 PfxDebug = concatstr(TiClrEol,colorstr(ColorDebug));
340 PfxInfo = concatstr(TiClrEol,colorstr(ColorInfo));
341 PfxWarn = makestr("%s%swarning: ",TiClrEol,colorstr(ColorWarn));
342 PfxStart = concatstr(TiClrEol,colorstr(ColorStart));
343 PfxOut = concatstr(TiClrEol,colorstr(ColorOut));
344 PfxError = concatstr(TiClrEol,colorstr(ColorError));
345 PfxFail = concatstr(TiClrEol,colorstr(ColorFail));
346 PfxDone = concatstr(TiClrEol,colorstr(ColorDone));
347 }
348
349
350