Asterisk - The Open Source Telephony Project  GIT-master-44aef04
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"
41 #include "asterisk/threadstorage.h"
42 
43 static int vt100compat;
44 
45 static char enddata[80] = "";
46 static char quitdata[80] = "";
47 
48 static const char * const termpath[] = {
49  "/usr/share/terminfo",
50  "/usr/local/share/misc/terminfo",
51  "/usr/lib/terminfo",
52  NULL
53  };
54 
56 
57 struct commonbuf {
58  short which;
60 };
61 
62 static 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) */
77 static short convshort(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 
92 int ast_term_init(void)
93 {
94  char *term = getenv("TERM");
95  char termfile[256] = "";
96  char buffer[512] = "";
97  int termfd = -1, parseokay = 0, i;
98 
99  if (ast_opt_no_color) {
100  return 0;
101  }
102 
103  if (!ast_opt_console) {
104  /* If any remote console is not compatible, we'll strip the color codes at that point */
105  vt100compat = 1;
106  goto end;
107  }
108 
109  if (!term) {
110  return 0;
111  }
112 
113  for (i = 0;; i++) {
114  if (termpath[i] == NULL) {
115  break;
116  }
117  snprintf(termfile, sizeof(termfile), "%s/%c/%s", termpath[i], *term, term);
118  termfd = open(termfile, O_RDONLY);
119  if (termfd > -1) {
120  break;
121  }
122  }
123  if (termfd > -1) {
124  int actsize = read(termfd, buffer, sizeof(buffer) - 1);
125  short sz_names = convshort(buffer + 2);
126  short sz_bools = convshort(buffer + 4);
127  short n_nums = convshort(buffer + 6);
128 
129  /* if ((sz_names + sz_bools) & 1)
130  sz_bools++; */
131 
132  if (sz_names + sz_bools + n_nums < actsize) {
133  /* Offset 13 is defined in /usr/include/term.h, though we do not
134  * include it here, as it conflicts with include/asterisk/term.h */
135  short max_colors = convshort(buffer + 12 + sz_names + sz_bools + 13 * 2);
136  if (max_colors > 0) {
137  vt100compat = 1;
138  }
139  parseokay = 1;
140  }
141  close(termfd);
142  }
143 
144  if (!parseokay) {
145  /* These comparisons should not be substrings nor case-insensitive, as
146  * terminal types are very particular about how they treat suffixes and
147  * capitalization. For example, terminal type 'linux-m' does NOT
148  * support color, while 'linux' does. Not even all vt100* terminals
149  * support color, either (e.g. 'vt100+fnkeys'). */
150  if (!strcmp(term, "linux")) {
151  vt100compat = 1;
152  } else if (!strcmp(term, "xterm")) {
153  vt100compat = 1;
154  } else if (!strcmp(term, "xterm-color")) {
155  vt100compat = 1;
156  } else if (!strcmp(term, "xterm-256color")) {
157  vt100compat = 1;
158  } else if (!strncmp(term, "Eterm", 5)) {
159  /* Both entries which start with Eterm support color */
160  vt100compat = 1;
161  } else if (!strcmp(term, "vt100")) {
162  vt100compat = 1;
163  } else if (!strncmp(term, "crt", 3)) {
164  /* Both crt terminals support color */
165  vt100compat = 1;
166  }
167  }
168 
169 end:
170  if (vt100compat) {
171  /* Make commands show up in nice colors */
173  snprintf(enddata, sizeof(enddata), "%c[%dm", ESC, COLOR_BLACK);
174  } else if (ast_opt_force_black_background) {
175  snprintf(enddata, sizeof(enddata), "%c[%d;%d;%dm", ESC, ATTR_RESET, COLOR_WHITE, COLOR_BLACK + 10);
176  } else {
177  snprintf(enddata, sizeof(enddata), "%c[%dm", ESC, ATTR_RESET);
178  }
179  snprintf(quitdata, sizeof(quitdata), "%c[%dm", ESC, ATTR_RESET);
180  }
181  return 0;
182 }
183 
184 char *term_color(char *outbuf, const char *inbuf, int fgcolor, int bgcolor, int maxout)
185 {
186  int attr = 0;
187 
188  if (!vt100compat) {
189  ast_copy_string(outbuf, inbuf, maxout);
190  return outbuf;
191  }
192  if (!fgcolor) {
193  ast_copy_string(outbuf, inbuf, maxout);
194  return outbuf;
195  }
196 
197  if (fgcolor & 128) {
199  fgcolor &= ~128;
200  }
201 
202  if (bgcolor) {
203  bgcolor &= ~128;
204  }
205 
207  fgcolor = opposite(fgcolor);
208  }
209 
211  if (!bgcolor) {
212  bgcolor = COLOR_BLACK;
213  }
214  snprintf(outbuf, maxout, "%c[%d;%d;%dm%s%s", ESC, attr, fgcolor, bgcolor + 10, inbuf, term_end());
215  } else {
216  snprintf(outbuf, maxout, "%c[%d;%dm%s%s", ESC, attr, fgcolor, inbuf, term_end());
217  }
218  return outbuf;
219 }
220 
221 static void check_fgcolor(int *fgcolor, int *attr)
222 {
224  if (*fgcolor & 128) {
225  *fgcolor &= ~128;
226  }
227 
229  *fgcolor = opposite(*fgcolor);
230  }
231 }
232 
233 static void check_bgcolor(int *bgcolor)
234 {
235  if (*bgcolor) {
236  *bgcolor &= ~128;
237  }
238 }
239 
240 static int check_colors_allowed(void)
241 {
242  return vt100compat;
243 }
244 
245 int ast_term_color_code(struct ast_str **str, int fgcolor, int bgcolor)
246 {
247  int attr = 0;
248 
249  if (!check_colors_allowed()) {
250  return -1;
251  }
252 
253  check_fgcolor(&fgcolor, &attr);
254  check_bgcolor(&bgcolor);
255 
257  ast_str_append(str, 0, "%c[%d;%d;%dm", ESC, attr, fgcolor, COLOR_BLACK + 10);
258  } else if (bgcolor) {
259  ast_str_append(str, 0, "%c[%d;%d;%dm", ESC, attr, fgcolor, bgcolor + 10);
260  } else {
261  ast_str_append(str, 0, "%c[%d;%dm", ESC, attr, fgcolor);
262  }
263 
264  return 0;
265 }
266 
267 char *term_color_code(char *outbuf, int fgcolor, int bgcolor, int maxout)
268 {
269  int attr = 0;
270 
271  if (!check_colors_allowed()) {
272  *outbuf = '\0';
273  return outbuf;
274  }
275 
276  check_fgcolor(&fgcolor, &attr);
277  check_bgcolor(&bgcolor);
278 
280  snprintf(outbuf, maxout, "%c[%d;%d;%dm", ESC, attr, fgcolor, COLOR_BLACK + 10);
281  } else if (bgcolor) {
282  snprintf(outbuf, maxout, "%c[%d;%d;%dm", ESC, attr, fgcolor, bgcolor + 10);
283  } else {
284  snprintf(outbuf, maxout, "%c[%d;%dm", ESC, attr, fgcolor);
285  }
286 
287  return outbuf;
288 }
289 
290 const char *ast_term_color(int fgcolor, int bgcolor)
291 {
292  struct commonbuf *cb = ast_threadstorage_get(&commonbuf, sizeof(*cb));
293  char *buf;
294 
295  if (!cb) {
296  return "";
297  }
298  buf = cb->buffer[cb->which++];
300  cb->which = 0;
301  }
302 
303  return term_color_code(buf, fgcolor, bgcolor, AST_TERM_MAX_ESCAPE_CHARS);
304 }
305 
306 const char *ast_term_reset(void)
307 {
308  return term_end();
309 }
310 
311 char *term_strip(char *outbuf, const char *inbuf, int maxout)
312 {
313  char *outbuf_ptr = outbuf;
314  const char *inbuf_ptr = inbuf;
315 
316  while (outbuf_ptr < outbuf + maxout) {
317  switch (*inbuf_ptr) {
318  case ESC:
319  while (*inbuf_ptr && (*inbuf_ptr != 'm'))
320  inbuf_ptr++;
321  break;
322  default:
323  *outbuf_ptr = *inbuf_ptr;
324  outbuf_ptr++;
325  }
326  if (! *inbuf_ptr)
327  break;
328  inbuf_ptr++;
329  }
330  return outbuf;
331 }
332 
333 /* filter escape sequences */
334 void term_filter_escapes(char *line)
335 {
336  int i;
337  int len = strlen(line);
338 
339  for (i = 0; i < len; i++) {
340  if (line[i] != ESC)
341  continue;
342  if ((i < (len - 2)) &&
343  (line[i + 1] == 0x5B)) {
344  switch (line[i + 2]) {
345  case 0x30:
346  case 0x31:
347  case 0x33:
348  continue;
349  }
350  }
351  /* replace ESC with a space */
352  line[i] = ' ';
353  }
354 }
355 
356 const char *term_end(void)
357 {
358  return enddata;
359 }
360 
361 const char *term_quit(void)
362 {
363  return quitdata;
364 }
#define AST_THREADSTORAGE(name)
Define a thread storage variable.
Definition: threadstorage.h:84
static void check_fgcolor(int *fgcolor, int *attr)
Definition: term.c:221
#define AST_TERM_MAX_ROTATING_BUFFERS
Definition: term.h:72
Asterisk locking-related definitions:
Asterisk main include file. File version handling, generic pbx functions.
void * ast_threadstorage_get(struct ast_threadstorage *ts, size_t init_size)
Retrieve thread storage.
#define ast_opt_force_black_background
Definition: options.h:131
static int vt100compat
Definition: term.c:43
static short convshort(char *s)
Definition: term.c:77
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
void term_filter_escapes(char *line)
Definition: term.c:334
#define COLOR_CYAN
Definition: term.h:59
#define COLOR_WHITE
Definition: term.h:61
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:1091
#define COLOR_GREEN
Definition: term.h:51
const char * str
Definition: app_jack.c:147
#define NULL
Definition: resample.c:96
static int inbuf(struct baseio *bio, FILE *fi)
utility used by inchar(), for base_encode()
Definitions to aid in the use of thread local storage.
char * end
Definition: eagi_proxy.c:73
static char enddata[80]
Definition: term.c:45
#define ast_opt_console
Definition: options.h:109
Utility functions.
#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:71
#define ATTR_BRIGHT
Definition: term.h:36
#define ast_opt_no_color
Definition: options.h:114
Definition: term.c:57
static char quitdata[80]
Definition: term.c:46
char * term_color_code(char *outbuf, int fgcolor, int bgcolor, int maxout)
Write a color sequence to a string.
Definition: term.c:267
static int check_colors_allowed(void)
Definition: term.c:240
#define COLOR_RED
Definition: term.h:49
#define COLOR_BLACK
Definition: term.h:47
const char * ast_term_color(int fgcolor, int bgcolor)
Return a color sequence string.
Definition: term.c:290
The descriptor of a dynamic string XXX storage will be optimized later if needed We use the ts field ...
Definition: strings.h:584
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:184
#define ATTR_RESET
Definition: term.h:35
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
const char * ast_term_reset(void)
Returns the terminal reset code.
Definition: term.c:306
char buffer[AST_TERM_MAX_ROTATING_BUFFERS][AST_TERM_MAX_ESCAPE_CHARS]
Definition: term.c:59
const char * term_end(void)
Definition: term.c:356
Prototypes for public functions only of internal interest,.
int ast_term_init(void)
Definition: term.c:92
#define ast_opt_light_background
Definition: options.h:130
int ast_term_color_code(struct ast_str **str, int fgcolor, int bgcolor)
Append a color sequence to an ast_str.
Definition: term.c:245
static void check_bgcolor(int *bgcolor)
Definition: term.c:233
static const char *const termpath[]
Definition: term.c:48
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:401
short which
Definition: term.c:58
static struct test_val b
Handy terminal functions for vt* terms.
#define COLOR_BLUE
Definition: term.h:55
#define ESC
Definition: term.h:30
#define COLOR_BROWN
Definition: term.h:53
char * term_strip(char *outbuf, const char *inbuf, int maxout)
Remove colorings from a specified string.
Definition: term.c:311
static int opposite(int color)
Definition: term.c:62
const char * term_quit(void)
Definition: term.c:361
#define COLOR_MAGENTA
Definition: term.h:57
static struct test_val a