Changeset 5619

Simplify console output handling.

Now we're using AMI and receiving events as structured key/value
messages we can just apply highlighting/colours as we want and don't
have to parse the output later.

Comitted by:  mjagdis
Date:  Feb 09 2010 * 00:23 (about 1 year ago)

Affected files:

callweaver/trunk/corelib/console.c (unified diff)

r5594r5619
11 /*
22 * CallWeaver -- An open source telephony toolkit.
33 *
4 * Copyright (C) 2007, Eris Associates Limited, UK
4 * Copyright (C) 2007,2010, Eris Associates Limited, UK
55 *
66 * Mike Jagdis <mjagdis@eris-associates.co.uk>
77 *
------
5959 #define CALLWEAVER_PROMPT "%s*CLI> "
6060
6161
62 static struct {
63 const char *on, *off;
64 } level_attr[] = {
65 [__CW_LOG_DEBUG] = { NULL, NULL },
66 [__CW_LOG_EVENT] = { NULL, NULL },
67 [__CW_LOG_NOTICE] = { NULL, NULL },
68 [__CW_LOG_WARNING] = { NULL, NULL },
69 [__CW_LOG_ERROR] = { NULL, NULL },
70 [__CW_LOG_VERBOSE] = { NULL, NULL },
71 [__CW_LOG_DTMF] = { NULL, NULL },
72 };
73
74 static const char *bold_on, *bold_off;
75
76
6277 const char *rl_basic_word_break_characters = " \t";
6378
6479
------
7994 static int matches_count;
8095
8196
82 static void smart_write(const char *buf, int len)
97 static void exit_prompt(void)
8398 {
8499 if (prompting && (option_console || option_remote)) {
85100 prompting = 0;
86101 if (clr_eol) {
87 terminal_write("\r", 1);
102 fputs("\r", stdout);
88103 fputs(clr_eol, stdout);
89104 } else
90 terminal_write("\r\n", 2);
105 fputs("\r\n", stdout);
91106 }
92
93 terminal_write(buf, len);
94107 }
95108
96109
97110 static void smart_page(int page, const struct cw_dynstr *ds, int lines)
98111 {
112 exit_prompt();
113
99114 if (page) {
100115 int rows, cols;
101116
------
107122 if (!(pager = getenv("PAGER")))
108123 pager = "more";
109124
110 smart_write("", 0);
111
112125 if ((fd = popen(pager, "w"))) {
113126 int ok = (fwrite(ds->data, ds->used, 1, fd) == 1);
114127 if (pclose(fd) == 0 && ok)
------
117130 }
118131 }
119132
120 smart_write(ds->data, ds->used);
133 fwrite(ds->data, 1, ds->used, stdout);
121134 }
122135
123136
------
287300 const int name_len;
288301 const int buf_len;
289302 char *buf;
290 const char *tail;
291 const int tail_len;
292303 } field[] = {
293 [F_DATE] = { "Date", sizeof("Date") - 1, sizeof(buf_date), buf_date, NULL, 0 },
294 [F_LEVEL] = { "Level", sizeof("Level") - 1, sizeof(buf_level), buf_level, "[", 1 },
295 [F_THREADID] = { "Thread ID", sizeof("Thread ID") - 1, sizeof(buf_threadid), buf_threadid, "]: ", 3 },
296 [F_FILE] = { "File", sizeof("File") - 1, sizeof(buf_file), buf_file, ":", 1 },
297 [F_LINE] = { "Line", sizeof("Line") - 1, sizeof(buf_line), buf_line, " ", 1 },
298 [F_FUNCTION] = { "Function", sizeof("Function") - 1, sizeof(buf_function), buf_function, ": ", 2 },
304 [F_DATE] = { "Date", sizeof("Date") - 1, sizeof(buf_date), buf_date },
305 [F_LEVEL] = { "Level", sizeof("Level") - 1, sizeof(buf_level), buf_level },
306 [F_THREADID] = { "Thread ID", sizeof("Thread ID") - 1, sizeof(buf_threadid), buf_threadid },
307 [F_FILE] = { "File", sizeof("File") - 1, sizeof(buf_file), buf_file },
308 [F_LINE] = { "Line", sizeof("Line") - 1, sizeof(buf_line), buf_line },
309 [F_FUNCTION] = { "Function", sizeof("Function") - 1, sizeof(buf_function), buf_function },
299310 };
300311 static int field_len[arraysize(field)];
301312 static char buf[32768];
------
395406 }
396407 }
397408 } else if (msgtype == MSG_RESPONSE) {
398 if (lkey == sizeof("Message")-1 && !memcmp(key, "Message", sizeof("Message") - 1))
399 smart_write(val, lval);
409 if (lkey == sizeof("Message")-1 && !memcmp(key, "Message", sizeof("Message") - 1)) {
410 exit_prompt();
411 fwrite(val, 1, lval, stdout);
412 }
400413 } else if (msgtype == MSG_FOLLOWS || msgtype == MSG_COMPLETION) {
401414 if (lkey != sizeof("Privilege")-1 || memcmp(key, "Privilege", sizeof("Privilege") - 1)) {
402415 state = 4;
------
448461 if (buf[pos] == '\n') {
449462 if (msgtype == MSG_EVENT) {
450463 if (lval != sizeof("--END MESSAGE--") - 1 || memcmp(key, "--END MESSAGE--", sizeof("--END MESSAGE--") - 1)) {
464 exit_prompt();
465
451466 if (level == CW_EVENT_NUM_PROGRESS) {
452467 /* Progress messages suppress input handling until
453468 * we get a null progress message to signify the end
454469 */
455470 if (lval) {
456 smart_write(key, lval);
471 fwrite(key, 1, lval, stdout);
457472 progress = 2;
458473 } else {
459 smart_write("\n", 1);
474 putchar('\n');
460475 progress = 0;
461476 }
462477 } else {
463478 if (progress == 2) {
479 putchar('\n');
464480 progress = 1;
465 smart_write("\n", 1);
466481 }
467482
468483 key[lval++] = '\n';
469484 if (level != CW_EVENT_NUM_VERBOSE) {
470 smart_write(field[F_DATE].buf, field_len[F_DATE]);
471 for (i = 1; i < arraysize(field); i++) {
472 terminal_write(field[i].buf, field_len[i]);
473 terminal_write(field[i].tail, field[i].tail_len);
474 }
485 fwrite(field[F_DATE].buf, 1, field_len[F_DATE], stdout);
486 if (level >= 0 && level < arraysize(level_attr) && level_attr[level].on)
487 terminal_write_attr(level_attr[level].on);
488 fwrite(field[F_LEVEL].buf, 1, field_len[F_LEVEL], stdout);
489 if (level >= 0 && level < arraysize(level_attr) && level_attr[level].off)
490 terminal_write_attr(level_attr[level].off);
491 putchar('[');
492 fwrite(field[F_THREADID].buf, 1, field_len[F_THREADID], stdout);
493 fwrite("]: ", 1, 3, stdout);
494 fwrite(field[F_FILE].buf, 1, field_len[F_FILE], stdout);
495 putchar(':');
496 fwrite(field[F_LINE].buf, 1, field_len[F_LINE], stdout);
497 putchar(' ');
498 if (bold_on)
499 terminal_write_attr(bold_on);
500 fwrite(field[F_FUNCTION].buf, 1, field_len[F_FUNCTION], stdout);
501 if (bold_off)
502 terminal_write_attr(bold_off);
503 fwrite(": ", 1, 2, stdout);
475504 }
476 smart_write(key, lval);
505 fwrite(key, 1, lval, stdout);
477506 }
478507 } else
479508 state = 0;
------
585614 CW_UNUSED(data);
586615
587616 rl_callback_handler_remove();
588 terminal_write("\r\n", 2);
617 fputs("\r\n", stdout);
589618 fflush(stdout);
590619 set_title("");
591620
------
729758 console_address = data;
730759 console_sock = -1;
731760
761 pthread_cleanup_push(console_cleanup, NULL);
762
732763 terminal_init();
764
765 terminal_highlight(&level_attr[__CW_LOG_DEBUG].on, &level_attr[__CW_LOG_DEBUG].off, "fg=blue,bold");
766 terminal_highlight(&level_attr[__CW_LOG_NOTICE].on, &level_attr[__CW_LOG_NOTICE].off, "fg=green,bold");
767 terminal_highlight(&level_attr[__CW_LOG_WARNING].on, &level_attr[__CW_LOG_WARNING].off, "fg=yellow,bold");
768 terminal_highlight(&level_attr[__CW_LOG_ERROR].on, &level_attr[__CW_LOG_ERROR].off, "fg=red,bold");
769
770 terminal_highlight(&bold_on, &bold_off, "bold");
771
733772 terminal_set_icon("Callweaver");
734773
735774 sigemptyset(&sigs);
736775 sigaddset(&sigs, SIGWINCH);
737776 pthread_sigmask(SIG_UNBLOCK, &sigs, NULL);
738777
739 pthread_cleanup_push(console_cleanup, NULL);
740
741778 rl_initialize ();
742779 rl_editing_mode = 1;
743780 rl_completion_entry_function = (rl_compentry_func_t *)dummy_completer; /* The typedef varies between platforms */

callweaver/trunk/corelib/terminal.c (unified diff)

r5594r5619
11 /*
22 * CallWeaver -- An open source telephony toolkit.
33 *
4 * Copyright (C) 2007, Eris Associates Limited, UK
4 * Copyright (C) 2007,2010, Eris Associates Limited, UK
55 *
66 * Mike Jagdis <mjagdis@eris-associates.co.uk>
77 *
------
4242
4343 static char *sgr, *setaf, *setab;
4444
45 static struct {
46 const char *on, *off;
47 } level_attr[] = {
48 [__CW_LOG_DEBUG] = { NULL, NULL },
49 [__CW_LOG_EVENT] = { NULL, NULL },
50 [__CW_LOG_NOTICE] = { NULL, NULL },
51 [__CW_LOG_WARNING] = { NULL, NULL },
52 [__CW_LOG_ERROR] = { NULL, NULL },
53 [__CW_LOG_VERBOSE] = { NULL, NULL },
54 [__CW_LOG_DTMF] = { NULL, NULL },
55 };
56
5745 static const char *col_defaults;
5846 static int col_defaults_len;
5947 static const char *attr_end;
6048 static int attr_end_len;
6149
6250
63 static void highlight(const char **start, const char **end, const char *spec)
51 void terminal_highlight(const char **start, const char **end, const char *spec)
6452 {
6553 static struct {
6654 int len;
------
193181 }
194182
195183
184 int terminal_write_attr(const char *str)
185 {
186 return putp(str);
187 }
188
189
196190 void terminal_init(void)
197191 {
198192 int i;
------
213207 attr_end_len = strlen(attr_end);
214208 } else
215209 sgr = NULL;
216
217 highlight(&level_attr[__CW_LOG_DEBUG].on, &level_attr[__CW_LOG_DEBUG].off, "fg=blue,bold");
218 highlight(&level_attr[__CW_LOG_NOTICE].on, &level_attr[__CW_LOG_NOTICE].off, "fg=green,bold");
219 highlight(&level_attr[__CW_LOG_WARNING].on, &level_attr[__CW_LOG_WARNING].off, "fg=yellow,bold");
220 highlight(&level_attr[__CW_LOG_ERROR].on, &level_attr[__CW_LOG_ERROR].off, "fg=red,bold");
221210 }
222211 }
223212 }
------
232221 fflush(stderr);
233222 }
234223 }
235
236
237 void terminal_write(const char *buf, int len)
238 {
239 static char word[80];
240 static int windex = 0;
241 static int state = 0;
242
243 while (len) {
244 if (state == 0) {
245 if (isalnum(*buf) || (len > 1 && strchr("/_.", *buf) && isalnum(buf[1])))
246 state = 1;
247 else if (*buf == ' ')
248 state = 2;
249 else if (ispunct(*buf))
250 state = 3;
251 else
252 state = 4;
253 }
254
255 switch (state) {
256 case 1:
257 while (len && (isalnum(*buf) || (len > 1 && strchr(":/_.", *buf) && isalnum(buf[1]))) && windex < sizeof(word)/sizeof(word[0])) {
258 len--;
259 word[windex++] = *(buf++);
260 }
261 break;
262
263 case 2:
264 while (len && *buf == ' ' && windex < sizeof(word)/sizeof(word[0])) {
265 len--;
266 word[windex++] = *(buf++);
267 }
268 break;
269
270 case 3:
271 while (len && ispunct(*buf) && (len <= 1 || !strchr("/_.", *buf) || !isalnum(buf[1])) && windex < sizeof(word)/sizeof(word[0])) {
272 len--;
273 word[windex++] = *(buf++);
274 }
275 break;
276
277 case 4:
278 //if (len && !isprint(*buf) && windex < sizeof(word)/sizeof(word[0])) {
279 len--;
280 word[windex++] = *(buf++);
281 state = 0;
282 //}
283 break;
284 }
285
286 if (len && windex < sizeof(word)/sizeof(word[0]))
287 state = 0;
288
289 if (len || windex < sizeof(word)/sizeof(word[0])) {
290 #if 1
291 int i = __CW_LOG_VERBOSE;
292
293 if (!strncmp(word, "DEBUG", windex))
294 i = __CW_LOG_DEBUG;
295 else if (!strncmp(word, "EVENT", windex))
296 i = __CW_LOG_EVENT;
297 else if (!strncmp(word, "NOTICE", windex))
298 i = __CW_LOG_NOTICE;
299 else if (!strncmp(word, "WARNING", windex))
300 i = __CW_LOG_WARNING;
301 else if (!strncmp(word, "ERROR", windex))
302 i = __CW_LOG_ERROR;
303 else if (!strncmp(word, "VERBOSE", windex))
304 i = __CW_LOG_VERBOSE;
305 else if (!strncmp(word, "DTMF", windex))
306 i = __CW_LOG_DTMF;
307
308 if (level_attr[i].on)
309 putp(level_attr[i].on);
310 fwrite(word, sizeof(word[0]), windex, stdout);
311 if (level_attr[i].off)
312 putp(level_attr[i].off);
313 #else
314 if (windex == 1 && !isprint(word[0])) {
315 printf("0x%02x\n", word[0]);
316 } else {
317 fprintf(stdout, "%d \"", windex);
318 fwrite(word, sizeof(word[0]), windex, stdout);
319 fputs("\"\n", stdout);
320 }
321 #endif
322
323 windex = 0;
324 }
325 }
326 }

callweaver/trunk/corelib/terminal.h (unified diff)

r4197r5619
11 /*
22 * CallWeaver -- An open source telephony toolkit.
33 *
4 * Copyright (C) 2007, Eris Associates Limited, UK
4 * Copyright (C) 2007,2010, Eris Associates Limited, UK
55 *
66 * Mike Jagdis <mjagdis@eris-associates.co.uk>
77 *
------
1616 * at the top of the source tree.
1717 */
1818
19 extern void terminal_highlight(const char **start, const char **end, const char *spec);
20 extern int terminal_write_attr(const char *str);
1921 extern void terminal_init(void);
2022 extern void terminal_set_icon(const char *s);
21 extern void terminal_write(const char *buf, int len);