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 (diff)
callweaver/trunk/corelib/terminal.c (diff)
callweaver/trunk/corelib/terminal.h (diff)
callweaver/trunk/corelib/console.c (unified diff)
| r5594 | r5619 | |
|---|---|---|
| 1 | 1 | /* |
| 2 | 2 | * CallWeaver -- An open source telephony toolkit. |
| 3 | 3 | * |
| 4 | * Copyright (C) 2007, Eris Associates Limited, UK | |
| 4 | * Copyright (C) 2007,2010, Eris Associates Limited, UK | |
| 5 | 5 | * |
| 6 | 6 | * Mike Jagdis <mjagdis@eris-associates.co.uk> |
| 7 | 7 | * |
| --- | --- | |
| 59 | 59 | #define CALLWEAVER_PROMPT "%s*CLI> " |
| 60 | 60 | |
| 61 | 61 | |
| 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 | ||
| 62 | 77 | const char *rl_basic_word_break_characters = " \t"; |
| 63 | 78 | |
| 64 | 79 | |
| --- | --- | |
| 79 | 94 | static int matches_count; |
| 80 | 95 | |
| 81 | 96 | |
| 82 | static void smart_write(const char *buf, int len) | |
| 97 | static void exit_prompt(void) | |
| 83 | 98 | { |
| 84 | 99 | if (prompting && (option_console || option_remote)) { |
| 85 | 100 | prompting = 0; |
| 86 | 101 | if (clr_eol) { |
| 87 | terminal_write("\r", 1); | |
| 102 | fputs("\r", stdout); | |
| 88 | 103 | fputs(clr_eol, stdout); |
| 89 | 104 | } else |
| 90 | terminal_write("\r\n", 2); | |
| 105 | fputs("\r\n", stdout); | |
| 91 | 106 | } |
| 92 | ||
| 93 | terminal_write(buf, len); | |
| 94 | 107 | } |
| 95 | 108 | |
| 96 | 109 | |
| 97 | 110 | static void smart_page(int page, const struct cw_dynstr *ds, int lines) |
| 98 | 111 | { |
| 112 | exit_prompt(); | |
| 113 | ||
| 99 | 114 | if (page) { |
| 100 | 115 | int rows, cols; |
| 101 | 116 | |
| --- | --- | |
| 107 | 122 | if (!(pager = getenv("PAGER"))) |
| 108 | 123 | pager = "more"; |
| 109 | 124 | |
| 110 | smart_write("", 0); | |
| 111 | ||
| 112 | 125 | if ((fd = popen(pager, "w"))) { |
| 113 | 126 | int ok = (fwrite(ds->data, ds->used, 1, fd) == 1); |
| 114 | 127 | if (pclose(fd) == 0 && ok) |
| --- | --- | |
| 117 | 130 | } |
| 118 | 131 | } |
| 119 | 132 | |
| 120 | smart_write(ds->data, ds->used); | |
| 133 | fwrite(ds->data, 1, ds->used, stdout); | |
| 121 | 134 | } |
| 122 | 135 | |
| 123 | 136 | |
| --- | --- | |
| 287 | 300 | const int name_len; |
| 288 | 301 | const int buf_len; |
| 289 | 302 | char *buf; |
| 290 | const char *tail; | |
| 291 | const int tail_len; | |
| 292 | 303 | } 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 }, | |
| 299 | 310 | }; |
| 300 | 311 | static int field_len[arraysize(field)]; |
| 301 | 312 | static char buf[32768]; |
| --- | --- | |
| 395 | 406 | } |
| 396 | 407 | } |
| 397 | 408 | } 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 | } | |
| 400 | 413 | } else if (msgtype == MSG_FOLLOWS || msgtype == MSG_COMPLETION) { |
| 401 | 414 | if (lkey != sizeof("Privilege")-1 || memcmp(key, "Privilege", sizeof("Privilege") - 1)) { |
| 402 | 415 | state = 4; |
| --- | --- | |
| 448 | 461 | if (buf[pos] == '\n') { |
| 449 | 462 | if (msgtype == MSG_EVENT) { |
| 450 | 463 | if (lval != sizeof("--END MESSAGE--") - 1 || memcmp(key, "--END MESSAGE--", sizeof("--END MESSAGE--") - 1)) { |
| 464 | exit_prompt(); | |
| 465 | ||
| 451 | 466 | if (level == CW_EVENT_NUM_PROGRESS) { |
| 452 | 467 | /* Progress messages suppress input handling until |
| 453 | 468 | * we get a null progress message to signify the end |
| 454 | 469 | */ |
| 455 | 470 | if (lval) { |
| 456 | smart_write(key, lval); | |
| 471 | fwrite(key, 1, lval, stdout); | |
| 457 | 472 | progress = 2; |
| 458 | 473 | } else { |
| 459 | smart_write("\n", 1); | |
| 474 | putchar('\n'); | |
| 460 | 475 | progress = 0; |
| 461 | 476 | } |
| 462 | 477 | } else { |
| 463 | 478 | if (progress == 2) { |
| 479 | putchar('\n'); | |
| 464 | 480 | progress = 1; |
| 465 | smart_write("\n", 1); | |
| 466 | 481 | } |
| 467 | 482 | |
| 468 | 483 | key[lval++] = '\n'; |
| 469 | 484 | 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); | |
| 475 | 504 | } |
| 476 | smart_write(key, lval); | |
| 505 | fwrite(key, 1, lval, stdout); | |
| 477 | 506 | } |
| 478 | 507 | } else |
| 479 | 508 | state = 0; |
| --- | --- | |
| 585 | 614 | CW_UNUSED(data); |
| 586 | 615 | |
| 587 | 616 | rl_callback_handler_remove(); |
| 588 | terminal_write("\r\n", 2); | |
| 617 | fputs("\r\n", stdout); | |
| 589 | 618 | fflush(stdout); |
| 590 | 619 | set_title(""); |
| 591 | 620 | |
| --- | --- | |
| 729 | 758 | console_address = data; |
| 730 | 759 | console_sock = -1; |
| 731 | 760 | |
| 761 | pthread_cleanup_push(console_cleanup, NULL); | |
| 762 | ||
| 732 | 763 | 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 | ||
| 733 | 772 | terminal_set_icon("Callweaver"); |
| 734 | 773 | |
| 735 | 774 | sigemptyset(&sigs); |
| 736 | 775 | sigaddset(&sigs, SIGWINCH); |
| 737 | 776 | pthread_sigmask(SIG_UNBLOCK, &sigs, NULL); |
| 738 | 777 | |
| 739 | pthread_cleanup_push(console_cleanup, NULL); | |
| 740 | ||
| 741 | 778 | rl_initialize (); |
| 742 | 779 | rl_editing_mode = 1; |
| 743 | 780 | rl_completion_entry_function = (rl_compentry_func_t *)dummy_completer; /* The typedef varies between platforms */ |
callweaver/trunk/corelib/terminal.c (unified diff)
| r5594 | r5619 | |
|---|---|---|
| 1 | 1 | /* |
| 2 | 2 | * CallWeaver -- An open source telephony toolkit. |
| 3 | 3 | * |
| 4 | * Copyright (C) 2007, Eris Associates Limited, UK | |
| 4 | * Copyright (C) 2007,2010, Eris Associates Limited, UK | |
| 5 | 5 | * |
| 6 | 6 | * Mike Jagdis <mjagdis@eris-associates.co.uk> |
| 7 | 7 | * |
| --- | --- | |
| 42 | 42 | |
| 43 | 43 | static char *sgr, *setaf, *setab; |
| 44 | 44 | |
| 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 | ||
| 57 | 45 | static const char *col_defaults; |
| 58 | 46 | static int col_defaults_len; |
| 59 | 47 | static const char *attr_end; |
| 60 | 48 | static int attr_end_len; |
| 61 | 49 | |
| 62 | 50 | |
| 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) | |
| 64 | 52 | { |
| 65 | 53 | static struct { |
| 66 | 54 | int len; |
| --- | --- | |
| 193 | 181 | } |
| 194 | 182 | |
| 195 | 183 | |
| 184 | int terminal_write_attr(const char *str) | |
| 185 | { | |
| 186 | return putp(str); | |
| 187 | } | |
| 188 | ||
| 189 | ||
| 196 | 190 | void terminal_init(void) |
| 197 | 191 | { |
| 198 | 192 | int i; |
| --- | --- | |
| 213 | 207 | attr_end_len = strlen(attr_end); |
| 214 | 208 | } else |
| 215 | 209 | 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"); | |
| 221 | 210 | } |
| 222 | 211 | } |
| 223 | 212 | } |
| --- | --- | |
| 232 | 221 | fflush(stderr); |
| 233 | 222 | } |
| 234 | 223 | } |
| 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)
| r4197 | r5619 | |
|---|---|---|
| 1 | 1 | /* |
| 2 | 2 | * CallWeaver -- An open source telephony toolkit. |
| 3 | 3 | * |
| 4 | * Copyright (C) 2007, Eris Associates Limited, UK | |
| 4 | * Copyright (C) 2007,2010, Eris Associates Limited, UK | |
| 5 | 5 | * |
| 6 | 6 | * Mike Jagdis <mjagdis@eris-associates.co.uk> |
| 7 | 7 | * |
| --- | --- | |
| 16 | 16 | * at the top of the source tree. |
| 17 | 17 | */ |
| 18 | 18 | |
| 19 | extern void terminal_highlight(const char **start, const char **end, const char *spec); | |
| 20 | extern int terminal_write_attr(const char *str); | |
| 19 | 21 | extern void terminal_init(void); |
| 20 | 22 | extern void terminal_set_icon(const char *s); |
| 21 | extern void terminal_write(const char *buf, int len); |
![Home changeset 5619 [home]](/images/logo.png?1180520111)

RSS Feeds