Asterisk - The Open Source Telephony Project GIT-master-7e7a603
term.c
Go to the documentation of this file.
1/*
2 * Asterisk -- An open source telephony toolkit.
3 *
4 * Copyright (C) 1999 - 2010, Digium, Inc.
5 *
6 * Mark Spencer <markster@digium.com>
7 *
8 * See http://www.asterisk.org for more information about
9 * the Asterisk project. Please do not directly contact
10 * any of the maintainers of this project for assistance;
11 * the project provides a web site, mailing lists and IRC
12 * channels for your use.
13 *
14 * This program is free software, distributed under the terms of
15 * the GNU General Public License Version 2. See the LICENSE file
16 * at the top of the source tree.
17 */
18
19/*! \file
20 *
21 * \brief Terminal Routines
22 *
23 * \author Mark Spencer <markster@digium.com>
24 */
25
26/*** MODULEINFO
27 <support_level>core</support_level>
28 ***/
29
30#include "asterisk.h"
31
32#include "asterisk/_private.h"
33#include <sys/time.h>
34#include <signal.h>
35#include <sys/stat.h>
36#include <fcntl.h>
37
38#include "asterisk/term.h"
39#include "asterisk/lock.h"
40#include "asterisk/utils.h"
42
43static int vt100compat;
44
45static char enddata[80] = "";
46static char quitdata[80] = "";
47
48static const char * const termpath[] = {
49 "/usr/share/terminfo",
50 "/usr/local/share/misc/terminfo",
51 "/usr/lib/terminfo",
52 NULL
53 };
54
56
57struct commonbuf {
58 short which;
60};
61
62static int opposite(int color)
63{
64 int lookup[] = {
65 /* BLACK */ COLOR_BLACK,
66 /* RED */ COLOR_MAGENTA,
67 /* GREEN */ COLOR_GREEN,
68 /* BROWN */ COLOR_BROWN,
69 /* BLUE */ COLOR_CYAN,
70 /* MAGENTA */ COLOR_RED,
71 /* CYAN */ COLOR_BLUE,
72 /* WHITE */ COLOR_BLACK };
73 return color ? lookup[color - 30] : 0;
74}
75
76/* Ripped off from Ross Ridge, but it's public domain code (libmytinfo) */
77static short convshort(unsigned char *s)
78{
79 register int a, b;
80
81 a = (int) s[0] & 0377;
82 b = (int) s[1] & 0377;
83
84 if (a == 0377 && b == 0377)
85 return -1;
86 if (a == 0376 && b == 0377)
87 return -2;
88
89 return a + b * 256;
90}
91
92static inline int convint(unsigned char *s)
93{
94 return s[0]
95 | s[1] << 8
96 | s[2] << 16
97 | s[3] << 24;
98}
99
100#define MAGIC_LEGACY (00432)
101#define MAGIC_EXTNUM (01036)
102
103#define HEADER_LEN (12)
104#define MAX_COLORS_INDEX (13)
105
106static int parse_terminfo_file(int fd)
107{
108 int bytes_read, bytes_needed, num_size;
109 short magic, sz_names, sz_bools;
110 unsigned char buffer[1024];
111
112 bytes_read = read(fd, buffer, sizeof(buffer));
113 if (bytes_read < HEADER_LEN) {
114 return 0;
115 }
116
117 magic = convshort(buffer);
118
119 if (magic == MAGIC_LEGACY) {
120 num_size = 2;
121 } else if (magic == MAGIC_EXTNUM) {
122 /* Extended number format (ncurses 6.1) */
123 num_size = 4;
124 } else {
125 /* We don't know how to parse this file */
126 return 0;
127 }
128
129 sz_names = convshort(buffer + 2);
130 sz_bools = convshort(buffer + 4);
131
132 /* From term(5):
133 * Between the boolean section and the number section, a null byte will be
134 * inserted, if necessary, to ensure that the number section begins on an
135 * even byte. */
136 if ((sz_names + sz_bools) & 1) {
137 sz_bools++;
138 }
139
140 bytes_needed = HEADER_LEN + sz_names + sz_bools + ((MAX_COLORS_INDEX + 1) * num_size);
141 if (bytes_needed <= bytes_read) {
142 /* Offset 13 is defined in /usr/include/term.h, though we do not
143 * include it here, as it conflicts with include/asterisk/term.h */
144 int max_colors;
145 int offset = HEADER_LEN + sz_names + sz_bools + MAX_COLORS_INDEX * num_size;
146
147 if (num_size == 2) {
148 /* In the legacy terminfo format, numbers are signed shorts */
149 max_colors = convshort(buffer + offset);
150 } else {
151 /* Extended number format makes them signed ints */
152 max_colors = convint(buffer + offset);
153 }
154
155 if (max_colors > 0) {
156 vt100compat = 1;
157 }
158
159 return 1;
160 }
161
162 return 0;
163}
164
166{
167 char *term = getenv("TERM");
168 char termfile[256] = "";
169 int termfd = -1, parseokay = 0, i;
170
171 if (ast_opt_no_color) {
172 return 0;
173 }
174
175 if (!ast_opt_console) {
176 /* If any remote console is not compatible, we'll strip the color codes at that point */
177 vt100compat = 1;
178 goto end;
179 }
180
181 if (!term) {
182 return 0;
183 }
184
185 for (i = 0; !parseokay && termpath[i]; i++) {
186 snprintf(termfile, sizeof(termfile), "%s/%c/%s", termpath[i], *term, term);
187
188 termfd = open(termfile, O_RDONLY);
189 if (termfd > -1) {
190 parseokay = parse_terminfo_file(termfd);
191 close(termfd);
192 }
193 }
194
195 if (!parseokay) {
196 /* These comparisons should not be substrings nor case-insensitive, as
197 * terminal types are very particular about how they treat suffixes and
198 * capitalization. For example, terminal type 'linux-m' does NOT
199 * support color, while 'linux' does. Not even all vt100* terminals
200 * support color, either (e.g. 'vt100+fnkeys'). */
201 if (!strcmp(term, "linux")) {
202 vt100compat = 1;
203 } else if (!strcmp(term, "xterm")) {
204 vt100compat = 1;
205 } else if (!strcmp(term, "xterm-color")) {
206 vt100compat = 1;
207 } else if (!strcmp(term, "xterm-256color")) {
208 vt100compat = 1;
209 } else if (!strncmp(term, "Eterm", 5)) {
210 /* Both entries which start with Eterm support color */
211 vt100compat = 1;
212 } else if (!strcmp(term, "vt100")) {
213 vt100compat = 1;
214 } else if (!strncmp(term, "crt", 3)) {
215 /* Both crt terminals support color */
216 vt100compat = 1;
217 }
218 }
219
220end:
221 if (vt100compat) {
222 /* Make commands show up in nice colors */
224 snprintf(enddata, sizeof(enddata), "%c[%dm", ESC, COLOR_BLACK);
226 snprintf(enddata, sizeof(enddata), "%c[%d;%d;%dm", ESC, ATTR_RESET, COLOR_WHITE, COLOR_BLACK + 10);
227 } else {
228 snprintf(enddata, sizeof(enddata), "%c[%dm", ESC, ATTR_RESET);
229 }
230 snprintf(quitdata, sizeof(quitdata), "%c[%dm", ESC, ATTR_RESET);
231 }
232 return 0;
233}
234
235char *term_color(char *outbuf, const char *inbuf, int fgcolor, int bgcolor, int maxout)
236{
237 int attr = 0;
238
239 if (!vt100compat) {
240 ast_copy_string(outbuf, inbuf, maxout);
241 return outbuf;
242 }
243 if (!fgcolor) {
244 ast_copy_string(outbuf, inbuf, maxout);
245 return outbuf;
246 }
247
248 if (fgcolor & 128) {
250 fgcolor &= ~128;
251 }
252
253 if (bgcolor) {
254 bgcolor &= ~128;
255 }
256
258 fgcolor = opposite(fgcolor);
259 }
260
262 if (!bgcolor) {
263 bgcolor = COLOR_BLACK;
264 }
265 snprintf(outbuf, maxout, "%c[%d;%d;%dm%s%s", ESC, attr, fgcolor, bgcolor + 10, inbuf, term_end());
266 } else {
267 snprintf(outbuf, maxout, "%c[%d;%dm%s%s", ESC, attr, fgcolor, inbuf, term_end());
268 }
269 return outbuf;
270}
271
272static void check_fgcolor(int *fgcolor, int *attr)
273{
275 if (*fgcolor & 128) {
276 *fgcolor &= ~128;
277 }
278
280 *fgcolor = opposite(*fgcolor);
281 }
282}
283
284static void check_bgcolor(int *bgcolor)
285{
286 if (*bgcolor) {
287 *bgcolor &= ~128;
288 }
289}
290
291static int check_colors_allowed(void)
292{
293 return vt100compat;
294}
295
296int ast_term_color_code(struct ast_str **str, int fgcolor, int bgcolor)
297{
298 int attr = 0;
299
300 if (!check_colors_allowed()) {
301 return -1;
302 }
303
304 check_fgcolor(&fgcolor, &attr);
305 check_bgcolor(&bgcolor);
306
308 ast_str_append(str, 0, "%c[%d;%d;%dm", ESC, attr, fgcolor, COLOR_BLACK + 10);
309 } else if (bgcolor) {
310 ast_str_append(str, 0, "%c[%d;%d;%dm", ESC, attr, fgcolor, bgcolor + 10);
311 } else {
312 ast_str_append(str, 0, "%c[%d;%dm", ESC, attr, fgcolor);
313 }
314
315 return 0;
316}
317
318char *term_color_code(char *outbuf, int fgcolor, int bgcolor, int maxout)
319{
320 int attr = 0;
321
322 if (!check_colors_allowed()) {
323 *outbuf = '\0';
324 return outbuf;
325 }
326
327 check_fgcolor(&fgcolor, &attr);
328 check_bgcolor(&bgcolor);
329
331 snprintf(outbuf, maxout, "%c[%d;%d;%dm", ESC, attr, fgcolor, COLOR_BLACK + 10);
332 } else if (bgcolor) {
333 snprintf(outbuf, maxout, "%c[%d;%d;%dm", ESC, attr, fgcolor, bgcolor + 10);
334 } else {
335 snprintf(outbuf, maxout, "%c[%d;%dm", ESC, attr, fgcolor);
336 }
337
338 return outbuf;
339}
340
341const char *ast_term_color(int fgcolor, int bgcolor)
342{
343 struct commonbuf *cb = ast_threadstorage_get(&commonbuf, sizeof(*cb));
344 char *buf;
345
346 if (!cb) {
347 return "";
348 }
349 buf = cb->buffer[cb->which++];
351 cb->which = 0;
352 }
353
354 return term_color_code(buf, fgcolor, bgcolor, AST_TERM_MAX_ESCAPE_CHARS);
355}
356
357const char *ast_term_reset(void)
358{
359 return term_end();
360}
361
362char *term_strip(char *outbuf, const char *inbuf, int maxout)
363{
364 char *outbuf_ptr = outbuf;
365 const char *inbuf_ptr = inbuf;
366
367 while (outbuf_ptr < outbuf + maxout) {
368 switch (*inbuf_ptr) {
369 case ESC:
370 while (*inbuf_ptr && (*inbuf_ptr != 'm'))
371 inbuf_ptr++;
372 break;
373 default:
374 *outbuf_ptr = *inbuf_ptr;
375 outbuf_ptr++;
376 }
377 if (! *inbuf_ptr)
378 break;
379 inbuf_ptr++;
380 }
381 return outbuf;
382}
383
384/* filter escape sequences */
385void term_filter_escapes(char *line)
386{
387 int i;
388 int len = strlen(line);
389
390 for (i = 0; i < len; i++) {
391 if (line[i] != ESC)
392 continue;
393 if ((i < (len - 2)) &&
394 (line[i + 1] == 0x5B)) {
395 switch (line[i + 2]) {
396 case 0x30:
397 case 0x31:
398 case 0x33:
399 continue;
400 }
401 }
402 /* replace ESC with a space */
403 line[i] = ' ';
404 }
405}
406
407const char *term_end(void)
408{
409 return enddata;
410}
411
412const char *term_quit(void)
413{
414 return quitdata;
415}
Prototypes for public functions only of internal interest,.
const char * str
Definition: app_jack.c:147
Asterisk main include file. File version handling, generic pbx functions.
char * end
Definition: eagi_proxy.c:73
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
Asterisk locking-related definitions:
#define ast_opt_console
Definition: options.h:111
#define ast_opt_no_color
Definition: options.h:116
#define ast_opt_force_black_background
Definition: options.h:131
#define ast_opt_light_background
Definition: options.h:130
#define NULL
Definition: resample.c:96
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
Definition: strings.h:1139
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:425
Support for dynamic strings.
Definition: strings.h:623
Definition: term.c:57
short which
Definition: term.c:58
char buffer[AST_TERM_MAX_ROTATING_BUFFERS][AST_TERM_MAX_ESCAPE_CHARS]
Definition: term.c:59
#define MAGIC_LEGACY
Definition: term.c:100
static int check_colors_allowed(void)
Definition: term.c:291
static int vt100compat
Definition: term.c:43
int ast_term_init(void)
Definition: term.c:165
const char * term_quit(void)
Definition: term.c:412
static short convshort(unsigned char *s)
Definition: term.c:77
int ast_term_color_code(struct ast_str **str, int fgcolor, int bgcolor)
Append a color sequence to an ast_str.
Definition: term.c:296
const char * ast_term_reset(void)
Returns the terminal reset code.
Definition: term.c:357
static int convint(unsigned char *s)
Definition: term.c:92
static char enddata[80]
Definition: term.c:45
static int parse_terminfo_file(int fd)
Definition: term.c:106
static char quitdata[80]
Definition: term.c:46
static void check_bgcolor(int *bgcolor)
Definition: term.c:284
const char * ast_term_color(int fgcolor, int bgcolor)
Return a color sequence string.
Definition: term.c:341
const char * term_end(void)
Definition: term.c:407
#define HEADER_LEN
Definition: term.c:103
char * term_color_code(char *outbuf, int fgcolor, int bgcolor, int maxout)
Write a color sequence to a string.
Definition: term.c:318
void term_filter_escapes(char *line)
Definition: term.c:385
char * term_color(char *outbuf, const char *inbuf, int fgcolor, int bgcolor, int maxout)
Colorize a specified string by adding terminal color codes.
Definition: term.c:235
#define MAGIC_EXTNUM
Definition: term.c:101
static void check_fgcolor(int *fgcolor, int *attr)
Definition: term.c:272
char * term_strip(char *outbuf, const char *inbuf, int maxout)
Remove colorings from a specified string.
Definition: term.c:362
static const char *const termpath[]
Definition: term.c:48
#define MAX_COLORS_INDEX
Definition: term.c:104
static int opposite(int color)
Definition: term.c:62
Handy terminal functions for vt* terms.
#define ATTR_BRIGHT
Definition: term.h:37
#define COLOR_BLUE
Definition: term.h:58
#define ESC
Definition: term.h:30
#define AST_TERM_MAX_ROTATING_BUFFERS
Definition: term.h:76
#define COLOR_CYAN
Definition: term.h:62
#define COLOR_MAGENTA
Definition: term.h:60
#define COLOR_BROWN
Definition: term.h:56
#define COLOR_WHITE
Definition: term.h:64
#define COLOR_BLACK
Definition: term.h:50
#define ATTR_RESET
Definition: term.h:36
#define AST_TERM_MAX_ESCAPE_CHARS
Maximum number of characters needed for a color escape sequence, and another one for a trailing reset...
Definition: term.h:75
#define COLOR_RED
Definition: term.h:52
#define COLOR_GREEN
Definition: term.h:54
static struct test_val b
static struct test_val a
Definitions to aid in the use of thread local storage.
void * ast_threadstorage_get(struct ast_threadstorage *ts, size_t init_size)
Retrieve thread storage.
#define AST_THREADSTORAGE(name)
Define a thread storage variable.
Definition: threadstorage.h:86
static int inbuf(struct baseio *bio, FILE *fi)
utility used by inchar(), for base_encode()
Definition: utils.c:590
Utility functions.