Mercurial > vim
comparison src/channel.c @ 7868:17e6ff1a74f1 v7.4.1231
commit https://github.com/vim/vim/commit/19d2f1589850d7db1ce77efec052929246f156e2
Author: Bram Moolenaar <Bram@vim.org>
Date: Mon Feb 1 21:38:19 2016 +0100
patch 7.4.1231
Problem: JSON messages are not parsed properly.
Solution: Queue received messages.
author | Christian Brabandt <cb@256bit.org> |
---|---|
date | Mon, 01 Feb 2016 21:45:06 +0100 |
parents | 6b0891de44a9 |
children | 4b9d4600166f |
comparison
equal
deleted
inserted
replaced
7867:3b79ecd05a51 | 7868:17e6ff1a74f1 |
---|---|
72 { | 72 { |
73 char_u *buffer; | 73 char_u *buffer; |
74 struct readqueue *next; | 74 struct readqueue *next; |
75 struct readqueue *prev; | 75 struct readqueue *prev; |
76 }; | 76 }; |
77 typedef struct readqueue queue_T; | 77 typedef struct readqueue readq_T; |
78 | |
79 struct jsonqueue | |
80 { | |
81 typval_T *value; | |
82 struct jsonqueue *next; | |
83 struct jsonqueue *prev; | |
84 }; | |
85 typedef struct jsonqueue jsonq_T; | |
78 | 86 |
79 typedef struct { | 87 typedef struct { |
80 sock_T ch_fd; /* the socket, -1 for a closed channel */ | 88 sock_T ch_fd; /* the socket, -1 for a closed channel */ |
81 int ch_idx; /* used by channel_poll_setup() */ | 89 int ch_idx; /* used by channel_poll_setup() */ |
82 queue_T ch_head; /* dummy node, header for circular queue */ | 90 readq_T ch_head; /* dummy node, header for circular queue */ |
83 | 91 |
84 int ch_error; /* When TRUE an error was reported. Avoids giving | 92 int ch_error; /* When TRUE an error was reported. Avoids giving |
85 * pages full of error messages when the other side | 93 * pages full of error messages when the other side |
86 * has exited, only mention the first error until the | 94 * has exited, only mention the first error until the |
87 * connection works again. */ | 95 * connection works again. */ |
98 void (*ch_close_cb)(void); /* callback for when channel is closed */ | 106 void (*ch_close_cb)(void); /* callback for when channel is closed */ |
99 | 107 |
100 char_u *ch_callback; /* function to call when a msg is not handled */ | 108 char_u *ch_callback; /* function to call when a msg is not handled */ |
101 char_u *ch_req_callback; /* function to call for current request */ | 109 char_u *ch_req_callback; /* function to call for current request */ |
102 | 110 |
103 int ch_json_mode; | 111 int ch_json_mode; /* TRUE for a json channel */ |
112 jsonq_T ch_json_head; /* dummy node, header for circular queue */ | |
104 } channel_T; | 113 } channel_T; |
105 | 114 |
106 /* | 115 /* |
107 * Information about all channels. | 116 * Information about all channels. |
108 * There can be gaps for closed channels, they will be reused later. | 117 * There can be gaps for closed channels, they will be reused later. |
123 static int | 132 static int |
124 add_channel(void) | 133 add_channel(void) |
125 { | 134 { |
126 int idx; | 135 int idx; |
127 channel_T *new_channels; | 136 channel_T *new_channels; |
137 channel_T *ch; | |
128 | 138 |
129 if (channels != NULL) | 139 if (channels != NULL) |
130 for (idx = 0; idx < channel_count; ++idx) | 140 for (idx = 0; idx < channel_count; ++idx) |
131 if (channels[idx].ch_fd < 0) | 141 if (channels[idx].ch_fd < 0) |
132 /* re-use a closed channel slot */ | 142 /* re-use a closed channel slot */ |
137 if (new_channels == NULL) | 147 if (new_channels == NULL) |
138 return -1; | 148 return -1; |
139 if (channels != NULL) | 149 if (channels != NULL) |
140 mch_memmove(new_channels, channels, sizeof(channel_T) * channel_count); | 150 mch_memmove(new_channels, channels, sizeof(channel_T) * channel_count); |
141 channels = new_channels; | 151 channels = new_channels; |
142 (void)vim_memset(&channels[channel_count], 0, sizeof(channel_T)); | 152 ch = &channels[channel_count]; |
143 | 153 (void)vim_memset(ch, 0, sizeof(channel_T)); |
144 channels[channel_count].ch_fd = (sock_T)-1; | 154 |
155 ch->ch_fd = (sock_T)-1; | |
145 #ifdef FEAT_GUI_X11 | 156 #ifdef FEAT_GUI_X11 |
146 channels[channel_count].ch_inputHandler = (XtInputId)NULL; | 157 ch->ch_inputHandler = (XtInputId)NULL; |
147 #endif | 158 #endif |
148 #ifdef FEAT_GUI_GTK | 159 #ifdef FEAT_GUI_GTK |
149 channels[channel_count].ch_inputHandler = 0; | 160 ch->ch_inputHandler = 0; |
150 #endif | 161 #endif |
151 #ifdef FEAT_GUI_W32 | 162 #ifdef FEAT_GUI_W32 |
152 channels[channel_count].ch_inputHandler = -1; | 163 ch->ch_inputHandler = -1; |
153 #endif | 164 #endif |
165 /* initialize circular queues */ | |
166 ch->ch_head.next = &ch->ch_head; | |
167 ch->ch_head.prev = &ch->ch_head; | |
168 ch->ch_json_head.next = &ch->ch_json_head; | |
169 ch->ch_json_head.prev = &ch->ch_json_head; | |
154 | 170 |
155 return channel_count++; | 171 return channel_count++; |
156 } | 172 } |
157 | 173 |
158 #if defined(FEAT_GUI) || defined(PROTO) | 174 #if defined(FEAT_GUI) || defined(PROTO) |
410 * Set the callback for channel "idx" for the next response. | 426 * Set the callback for channel "idx" for the next response. |
411 */ | 427 */ |
412 void | 428 void |
413 channel_set_req_callback(int idx, char_u *callback) | 429 channel_set_req_callback(int idx, char_u *callback) |
414 { | 430 { |
431 /* TODO: make a list of callbacks */ | |
415 vim_free(channels[idx].ch_req_callback); | 432 vim_free(channels[idx].ch_req_callback); |
416 channels[idx].ch_req_callback = callback == NULL | 433 channels[idx].ch_req_callback = callback == NULL |
417 ? NULL : vim_strsave(callback); | 434 ? NULL : vim_strsave(callback); |
418 } | |
419 | |
420 /* | |
421 * Decode JSON "msg", which must have the form "[expr1, expr2, expr3]". | |
422 * Put "expr1" in "tv1". | |
423 * Put "expr2" in "tv2". | |
424 * Put "expr3" in "tv3". If "tv3" is NULL there is no "expr3". | |
425 * | |
426 * Return OK or FAIL. | |
427 */ | |
428 int | |
429 channel_decode_json(char_u *msg, typval_T *tv1, typval_T *tv2, typval_T *tv3) | |
430 { | |
431 js_read_T reader; | |
432 typval_T listtv; | |
433 | |
434 reader.js_buf = msg; | |
435 reader.js_eof = TRUE; | |
436 reader.js_used = 0; | |
437 json_decode(&reader, &listtv); | |
438 | |
439 if (listtv.v_type == VAR_LIST) | |
440 { | |
441 list_T *list = listtv.vval.v_list; | |
442 | |
443 if (list->lv_len == 2 || (tv3 != NULL && list->lv_len == 3)) | |
444 { | |
445 /* Move the item from the list and then change the type to avoid the | |
446 * item being freed. */ | |
447 *tv1 = list->lv_first->li_tv; | |
448 list->lv_first->li_tv.v_type = VAR_NUMBER; | |
449 *tv2 = list->lv_first->li_next->li_tv; | |
450 list->lv_first->li_next->li_tv.v_type = VAR_NUMBER; | |
451 if (tv3 != NULL) | |
452 { | |
453 if (list->lv_len == 3) | |
454 { | |
455 *tv3 = list->lv_last->li_tv; | |
456 list->lv_last->li_tv.v_type = VAR_NUMBER; | |
457 } | |
458 else | |
459 tv3->v_type = VAR_UNKNOWN; | |
460 } | |
461 list_unref(list); | |
462 return OK; | |
463 } | |
464 } | |
465 | |
466 /* give error message? */ | |
467 clear_tv(&listtv); | |
468 return FAIL; | |
469 } | 435 } |
470 | 436 |
471 /* | 437 /* |
472 * Invoke the "callback" on channel "idx". | 438 * Invoke the "callback" on channel "idx". |
473 */ | 439 */ |
488 cursor_on(); | 454 cursor_on(); |
489 out_flush(); | 455 out_flush(); |
490 } | 456 } |
491 | 457 |
492 /* | 458 /* |
459 * Return the first buffer from the channel and remove it. | |
460 * The caller must free it. | |
461 * Returns NULL if there is nothing. | |
462 */ | |
463 char_u * | |
464 channel_get(int idx) | |
465 { | |
466 readq_T *head = &channels[idx].ch_head; | |
467 readq_T *node; | |
468 char_u *p; | |
469 | |
470 if (head->next == head || head->next == NULL) | |
471 return NULL; | |
472 node = head->next; | |
473 /* dispose of the node but keep the buffer */ | |
474 p = node->buffer; | |
475 head->next = node->next; | |
476 node->next->prev = node->prev; | |
477 vim_free(node); | |
478 return p; | |
479 } | |
480 | |
481 /* | |
482 * Returns the whole buffer contents concatenated. | |
483 */ | |
484 static char_u * | |
485 channel_get_all(int idx) | |
486 { | |
487 /* Concatenate everything into one buffer. | |
488 * TODO: avoid multiple allocations. */ | |
489 while (channel_collapse(idx) == OK) | |
490 ; | |
491 return channel_get(idx); | |
492 } | |
493 | |
494 /* | |
495 * Collapses the first and second buffer in the channel "idx". | |
496 * Returns FAIL if that is not possible. | |
497 */ | |
498 int | |
499 channel_collapse(int idx) | |
500 { | |
501 readq_T *head = &channels[idx].ch_head; | |
502 readq_T *node = head->next; | |
503 char_u *p; | |
504 | |
505 if (node == head || node == NULL || node->next == head) | |
506 return FAIL; | |
507 | |
508 p = alloc((unsigned)(STRLEN(node->buffer) | |
509 + STRLEN(node->next->buffer) + 1)); | |
510 if (p == NULL) | |
511 return FAIL; /* out of memory */ | |
512 STRCPY(p, node->buffer); | |
513 STRCAT(p, node->next->buffer); | |
514 vim_free(node->next->buffer); | |
515 node->next->buffer = p; | |
516 | |
517 /* dispose of the node and buffer */ | |
518 head->next = node->next; | |
519 node->next->prev = node->prev; | |
520 vim_free(node->buffer); | |
521 vim_free(node); | |
522 return OK; | |
523 } | |
524 | |
525 /* | |
526 * Use the read buffer of channel "ch_idx" and parse JSON messages that are | |
527 * complete. The messages are added to the queue. | |
528 */ | |
529 void | |
530 channel_read_json(int ch_idx) | |
531 { | |
532 js_read_T reader; | |
533 typval_T listtv; | |
534 jsonq_T *item; | |
535 jsonq_T *head = &channels[ch_idx].ch_json_head; | |
536 | |
537 if (channel_peek(ch_idx) == NULL) | |
538 return; | |
539 | |
540 /* TODO: make reader work properly */ | |
541 /* reader.js_buf = channel_peek(ch_idx); */ | |
542 reader.js_buf = channel_get_all(ch_idx); | |
543 reader.js_eof = TRUE; | |
544 /* reader.js_eof = FALSE; */ | |
545 reader.js_used = 0; | |
546 /* reader.js_fill = channel_fill; */ | |
547 reader.js_cookie = &ch_idx; | |
548 if (json_decode(&reader, &listtv) == OK) | |
549 { | |
550 item = (jsonq_T *)alloc((unsigned)sizeof(jsonq_T)); | |
551 if (item == NULL) | |
552 clear_tv(&listtv); | |
553 else | |
554 { | |
555 item->value = alloc_tv(); | |
556 if (item->value == NULL) | |
557 { | |
558 vim_free(item); | |
559 clear_tv(&listtv); | |
560 } | |
561 else | |
562 { | |
563 *item->value = listtv; | |
564 item->prev = head->prev; | |
565 head->prev = item; | |
566 item->next = head; | |
567 item->prev->next = item; | |
568 } | |
569 } | |
570 } | |
571 } | |
572 | |
573 /* | |
574 * Remove "node" from the queue that it is in and free it. | |
575 * Caller should have freed or used node->value. | |
576 */ | |
577 static void | |
578 remove_json_node(jsonq_T *node) | |
579 { | |
580 node->prev->next = node->next; | |
581 node->next->prev = node->prev; | |
582 vim_free(node); | |
583 } | |
584 | |
585 /* | |
586 * Get a message from the JSON queue for channel "ch_idx". | |
587 * When "id" is positive it must match the first number in the list. | |
588 * When "id" is zero or negative jut get the first message. | |
589 * Return OK when found and return the value in "rettv". | |
590 * Return FAIL otherwise. | |
591 */ | |
592 static int | |
593 channel_get_json(int ch_idx, int id, typval_T **rettv) | |
594 { | |
595 jsonq_T *head = &channels[ch_idx].ch_json_head; | |
596 jsonq_T *item = head->next; | |
597 | |
598 while (item != head) | |
599 { | |
600 list_T *l = item->value->vval.v_list; | |
601 typval_T *tv = &l->lv_first->li_tv; | |
602 | |
603 if ((id > 0 && tv->v_type == VAR_NUMBER && tv->vval.v_number == id) | |
604 || id <= 0) | |
605 { | |
606 *rettv = item->value; | |
607 remove_json_node(item); | |
608 return OK; | |
609 } | |
610 item = item->next; | |
611 } | |
612 return FAIL; | |
613 } | |
614 | |
615 /* | |
493 * Execute a command received over channel "idx". | 616 * Execute a command received over channel "idx". |
494 * "cmd" is the command string, "arg2" the second argument. | 617 * "cmd" is the command string, "arg2" the second argument. |
495 * "arg3" is the third argument, NULL if missing. | 618 * "arg3" is the third argument, NULL if missing. |
496 */ | 619 */ |
497 static void | 620 static void |
522 } | 645 } |
523 else if (STRCMP(cmd, "redraw") == 0) | 646 else if (STRCMP(cmd, "redraw") == 0) |
524 { | 647 { |
525 exarg_T ea; | 648 exarg_T ea; |
526 | 649 |
527 ea.forceit = *arg != NUL; | 650 ea.forceit = arg != NULL && *arg != NUL; |
528 ex_redraw(&ea); | 651 ex_redraw(&ea); |
529 showruler(FALSE); | 652 showruler(FALSE); |
530 setcursor(); | 653 setcursor(); |
531 out_flush(); | 654 out_flush(); |
532 #ifdef FEAT_GUI | 655 #ifdef FEAT_GUI |
575 * Invoke a callback for channel "idx" if needed. | 698 * Invoke a callback for channel "idx" if needed. |
576 */ | 699 */ |
577 static void | 700 static void |
578 may_invoke_callback(int idx) | 701 may_invoke_callback(int idx) |
579 { | 702 { |
580 char_u *msg; | 703 char_u *msg = NULL; |
581 typval_T typetv; | 704 typval_T *listtv = NULL; |
705 list_T *list; | |
706 typval_T *typetv; | |
582 typval_T argv[3]; | 707 typval_T argv[3]; |
583 typval_T arg3; | |
584 char_u *cmd = NULL; | |
585 int seq_nr = -1; | 708 int seq_nr = -1; |
586 int ret = OK; | 709 int json_mode = channels[idx].ch_json_mode; |
587 | 710 |
588 if (channel_peek(idx) == NULL) | 711 if (channel_peek(idx) == NULL) |
589 return; | 712 return; |
590 | 713 if (channels[idx].ch_close_cb != NULL) |
591 /* Concatenate everything into one buffer. | 714 /* this channel is handled elsewhere (netbeans) */ |
592 * TODO: only read what the callback will use. | 715 return; |
593 * TODO: avoid multiple allocations. */ | 716 |
594 while (channel_collapse(idx) == OK) | 717 if (json_mode) |
595 ; | 718 { |
596 msg = channel_get(idx); | 719 /* Get any json message. Return if there isn't one. */ |
597 | 720 channel_read_json(idx); |
598 if (channels[idx].ch_json_mode) | 721 if (channel_get_json(idx, -1, &listtv) == FAIL) |
599 { | 722 return; |
600 ret = channel_decode_json(msg, &typetv, &argv[1], &arg3); | 723 if (listtv->v_type != VAR_LIST) |
601 if (ret == OK) | 724 { |
602 { | 725 /* TODO: give error */ |
603 /* TODO: error if arg3 is set when it shouldn't? */ | 726 clear_tv(listtv); |
604 if (typetv.v_type == VAR_STRING) | 727 return; |
605 cmd = typetv.vval.v_string; | 728 } |
606 else if (typetv.v_type == VAR_NUMBER) | 729 |
607 seq_nr = typetv.vval.v_number; | 730 list = listtv->vval.v_list; |
608 } | 731 if (list->lv_len < 2) |
732 { | |
733 /* TODO: give error */ | |
734 clear_tv(listtv); | |
735 return; | |
736 } | |
737 | |
738 argv[1] = list->lv_first->li_next->li_tv; | |
739 typetv = &list->lv_first->li_tv; | |
740 if (typetv->v_type == VAR_STRING) | |
741 { | |
742 typval_T *arg3 = NULL; | |
743 char_u *cmd = typetv->vval.v_string; | |
744 | |
745 /* ["cmd", arg] */ | |
746 if (list->lv_len == 3) | |
747 arg3 = &list->lv_last->li_tv; | |
748 channel_exe_cmd(idx, cmd, &argv[1], arg3); | |
749 clear_tv(listtv); | |
750 return; | |
751 } | |
752 | |
753 if (typetv->v_type != VAR_NUMBER) | |
754 { | |
755 /* TODO: give error */ | |
756 clear_tv(listtv); | |
757 return; | |
758 } | |
759 seq_nr = typetv->vval.v_number; | |
609 } | 760 } |
610 else | 761 else |
611 { | 762 { |
763 /* For a raw channel we don't know where the message ends, just get | |
764 * everything. */ | |
765 msg = channel_get_all(idx); | |
612 argv[1].v_type = VAR_STRING; | 766 argv[1].v_type = VAR_STRING; |
613 argv[1].vval.v_string = msg; | 767 argv[1].vval.v_string = msg; |
614 } | 768 } |
615 | 769 |
616 if (ret == OK) | 770 if (channels[idx].ch_req_callback != NULL && seq_nr != 0) |
617 { | 771 { |
618 if (cmd != NULL) | 772 /* TODO: check the sequence number */ |
619 { | 773 /* invoke the one-time callback */ |
620 channel_exe_cmd(idx, cmd, &argv[1], &arg3); | 774 invoke_callback(idx, channels[idx].ch_req_callback, argv); |
621 } | 775 channels[idx].ch_req_callback = NULL; |
622 else if (channels[idx].ch_req_callback != NULL && seq_nr != 0) | 776 } |
623 { | 777 else if (channels[idx].ch_callback != NULL) |
624 /* TODO: check the sequence number */ | 778 { |
625 /* invoke the one-time callback */ | 779 /* invoke the channel callback */ |
626 invoke_callback(idx, channels[idx].ch_req_callback, argv); | 780 invoke_callback(idx, channels[idx].ch_callback, argv); |
627 channels[idx].ch_req_callback = NULL; | 781 } |
628 } | 782 /* else: drop the message TODO: give error */ |
629 else if (channels[idx].ch_callback != NULL) | 783 |
630 { | 784 if (listtv != NULL) |
631 /* invoke the channel callback */ | 785 clear_tv(listtv); |
632 invoke_callback(idx, channels[idx].ch_callback, argv); | |
633 } | |
634 /* else: drop the message */ | |
635 | |
636 if (channels[idx].ch_json_mode) | |
637 { | |
638 clear_tv(&typetv); | |
639 clear_tv(&argv[1]); | |
640 clear_tv(&arg3); | |
641 } | |
642 } | |
643 | |
644 vim_free(msg); | 786 vim_free(msg); |
645 } | 787 } |
646 | 788 |
647 /* | 789 /* |
648 * Return TRUE when channel "idx" is open. | 790 * Return TRUE when channel "idx" is open. |
659 * This does not trigger the close callback. | 801 * This does not trigger the close callback. |
660 */ | 802 */ |
661 void | 803 void |
662 channel_close(int idx) | 804 channel_close(int idx) |
663 { | 805 { |
664 channel_T *channel = &channels[idx]; | 806 channel_T *channel = &channels[idx]; |
807 jsonq_T *jhead; | |
665 | 808 |
666 if (channel->ch_fd >= 0) | 809 if (channel->ch_fd >= 0) |
667 { | 810 { |
668 sock_close(channel->ch_fd); | 811 sock_close(channel->ch_fd); |
669 channel->ch_fd = -1; | 812 channel->ch_fd = -1; |
813 channel->ch_close_cb = NULL; | |
670 #ifdef FEAT_GUI | 814 #ifdef FEAT_GUI |
671 channel_gui_unregister(idx); | 815 channel_gui_unregister(idx); |
672 #endif | 816 #endif |
673 vim_free(channel->ch_callback); | 817 vim_free(channel->ch_callback); |
674 channel->ch_callback = NULL; | 818 channel->ch_callback = NULL; |
819 | |
820 while (channel_peek(idx) != NULL) | |
821 vim_free(channel_get(idx)); | |
822 | |
823 jhead = &channel->ch_json_head; | |
824 while (jhead->next != jhead) | |
825 { | |
826 clear_tv(jhead->next->value); | |
827 remove_json_node(jhead->next); | |
828 } | |
675 } | 829 } |
676 } | 830 } |
677 | 831 |
678 /* | 832 /* |
679 * Store "buf[len]" on channel "idx". | 833 * Store "buf[len]" on channel "idx". |
680 * Returns OK or FAIL. | 834 * Returns OK or FAIL. |
681 */ | 835 */ |
682 int | 836 int |
683 channel_save(int idx, char_u *buf, int len) | 837 channel_save(int idx, char_u *buf, int len) |
684 { | 838 { |
685 queue_T *node; | 839 readq_T *node; |
686 queue_T *head = &channels[idx].ch_head; | 840 readq_T *head = &channels[idx].ch_head; |
687 | 841 |
688 node = (queue_T *)alloc(sizeof(queue_T)); | 842 node = (readq_T *)alloc(sizeof(readq_T)); |
689 if (node == NULL) | 843 if (node == NULL) |
690 return FAIL; /* out of memory */ | 844 return FAIL; /* out of memory */ |
691 node->buffer = alloc(len + 1); | 845 node->buffer = alloc(len + 1); |
692 if (node->buffer == NULL) | 846 if (node->buffer == NULL) |
693 { | 847 { |
694 vim_free(node); | 848 vim_free(node); |
695 return FAIL; /* out of memory */ | 849 return FAIL; /* out of memory */ |
696 } | 850 } |
697 mch_memmove(node->buffer, buf, (size_t)len); | 851 mch_memmove(node->buffer, buf, (size_t)len); |
698 node->buffer[len] = NUL; | 852 node->buffer[len] = NUL; |
699 | |
700 if (head->next == NULL) /* initialize circular queue */ | |
701 { | |
702 head->next = head; | |
703 head->prev = head; | |
704 } | |
705 | 853 |
706 /* insert node at tail of queue */ | 854 /* insert node at tail of queue */ |
707 node->next = head; | 855 node->next = head; |
708 node->prev = head->prev; | 856 node->prev = head->prev; |
709 head->prev->next = node; | 857 head->prev->next = node; |
724 * Returns NULL if there is nothing. | 872 * Returns NULL if there is nothing. |
725 */ | 873 */ |
726 char_u * | 874 char_u * |
727 channel_peek(int idx) | 875 channel_peek(int idx) |
728 { | 876 { |
729 queue_T *head = &channels[idx].ch_head; | 877 readq_T *head = &channels[idx].ch_head; |
730 | 878 |
731 if (head->next == head || head->next == NULL) | 879 if (head->next == head || head->next == NULL) |
732 return NULL; | 880 return NULL; |
733 return head->next->buffer; | 881 return head->next->buffer; |
734 } | 882 } |
735 | 883 |
736 /* | 884 /* |
737 * Return the first buffer from the channel and remove it. | |
738 * The caller must free it. | |
739 * Returns NULL if there is nothing. | |
740 */ | |
741 char_u * | |
742 channel_get(int idx) | |
743 { | |
744 queue_T *head = &channels[idx].ch_head; | |
745 queue_T *node; | |
746 char_u *p; | |
747 | |
748 if (head->next == head || head->next == NULL) | |
749 return NULL; | |
750 node = head->next; | |
751 /* dispose of the node but keep the buffer */ | |
752 p = node->buffer; | |
753 head->next = node->next; | |
754 node->next->prev = node->prev; | |
755 vim_free(node); | |
756 return p; | |
757 } | |
758 | |
759 /* | |
760 * Collapses the first and second buffer in the channel "idx". | |
761 * Returns FAIL if that is not possible. | |
762 */ | |
763 int | |
764 channel_collapse(int idx) | |
765 { | |
766 queue_T *head = &channels[idx].ch_head; | |
767 queue_T *node = head->next; | |
768 char_u *p; | |
769 | |
770 if (node == head || node == NULL || node->next == head) | |
771 return FAIL; | |
772 | |
773 p = alloc((unsigned)(STRLEN(node->buffer) | |
774 + STRLEN(node->next->buffer) + 1)); | |
775 if (p == NULL) | |
776 return FAIL; /* out of memory */ | |
777 STRCPY(p, node->buffer); | |
778 STRCAT(p, node->next->buffer); | |
779 vim_free(node->next->buffer); | |
780 node->next->buffer = p; | |
781 | |
782 /* dispose of the node and buffer */ | |
783 head->next = node->next; | |
784 node->next->prev = node->prev; | |
785 vim_free(node->buffer); | |
786 vim_free(node); | |
787 return OK; | |
788 } | |
789 | |
790 /* | |
791 * Clear the read buffer on channel "idx". | 885 * Clear the read buffer on channel "idx". |
792 */ | 886 */ |
793 void | 887 void |
794 channel_clear(int idx) | 888 channel_clear(int idx) |
795 { | 889 { |
796 queue_T *head = &channels[idx].ch_head; | 890 readq_T *head = &channels[idx].ch_head; |
797 queue_T *node = head->next; | 891 readq_T *node = head->next; |
798 queue_T *next; | 892 readq_T *next; |
799 | 893 |
800 while (node != NULL && node != head) | 894 while (node != NULL && node != head) |
801 { | 895 { |
802 next = node->next; | 896 next = node->next; |
803 vim_free(node->buffer); | 897 vim_free(node->buffer); |
945 gtk_main_quit(); | 1039 gtk_main_quit(); |
946 #endif | 1040 #endif |
947 } | 1041 } |
948 | 1042 |
949 /* | 1043 /* |
950 * Read from channel "idx". Blocks until there is something to read or the | 1044 * Read from raw channel "idx". Blocks until there is something to read or |
951 * timeout expires. | 1045 * the timeout expires. |
952 * Returns what was read in allocated memory. | 1046 * Returns what was read in allocated memory. |
953 * Returns NULL in case of error or timeout. | 1047 * Returns NULL in case of error or timeout. |
954 */ | 1048 */ |
955 char_u * | 1049 char_u * |
956 channel_read_block(int idx) | 1050 channel_read_block(int idx) |
962 if (channel_wait(channels[idx].ch_fd, 2000) == FAIL) | 1056 if (channel_wait(channels[idx].ch_fd, 2000) == FAIL) |
963 return NULL; | 1057 return NULL; |
964 channel_read(idx); | 1058 channel_read(idx); |
965 } | 1059 } |
966 | 1060 |
967 /* Concatenate everything into one buffer. | 1061 return channel_get_all(idx); |
968 * TODO: avoid multiple allocations. */ | 1062 } |
969 while (channel_collapse(idx) == OK) | 1063 |
970 ; | 1064 /* |
971 | 1065 * Read one JSON message from channel "ch_idx" with ID "id" and store the |
972 return channel_get(idx); | 1066 * result in "rettv". |
1067 * Blocks until the message is received. | |
1068 */ | |
1069 int | |
1070 channel_read_json_block(int ch_idx, int id, typval_T **rettv) | |
1071 { | |
1072 for (;;) | |
1073 { | |
1074 channel_read_json(ch_idx); | |
1075 | |
1076 /* search for messsage "id" */ | |
1077 if (channel_get_json(ch_idx, id, rettv) == OK) | |
1078 return OK; | |
1079 | |
1080 /* Wait for up to 2 seconds. | |
1081 * TODO: use timeout set on the channel. */ | |
1082 if (channel_wait(channels[ch_idx].ch_fd, 2000) == FAIL) | |
1083 break; | |
1084 channel_read(ch_idx); | |
1085 } | |
1086 return FAIL; | |
973 } | 1087 } |
974 | 1088 |
975 # if defined(WIN32) || defined(PROTO) | 1089 # if defined(WIN32) || defined(PROTO) |
976 /* | 1090 /* |
977 * Lookup the channel index from the socket. | 1091 * Lookup the channel index from the socket. |