comparison src/channel.c @ 8498:42277980a76d v7.4.1539

commit https://github.com/vim/vim/commit/8e2c942ce49f2555d7dc2088cf3aa856820c5e32 Author: Bram Moolenaar <Bram@vim.org> Date: Sat Mar 12 13:43:33 2016 +0100 patch 7.4.1539 Problem: Too much code in eval.c. Solution: Move job and channel code to channel.c.
author Christian Brabandt <cb@256bit.org>
date Sat, 12 Mar 2016 13:45:04 +0100
parents caed4b2d305f
children ee5cb2e9ed5a
comparison
equal deleted inserted replaced
8497:da01d5da2cfa 8498:42277980a76d
95 #ifdef FEAT_RELTIME 95 #ifdef FEAT_RELTIME
96 static proftime_T log_start; 96 static proftime_T log_start;
97 #endif 97 #endif
98 98
99 void 99 void
100 ch_logfile(FILE *file) 100 ch_logfile(char_u *fname, char_u *opt)
101 { 101 {
102 FILE *file = NULL;
103
102 if (log_fd != NULL) 104 if (log_fd != NULL)
103 fclose(log_fd); 105 fclose(log_fd);
106
107 if (*fname != NUL)
108 {
109 file = fopen((char *)fname, *opt == 'w' ? "w" : "a");
110 if (file == NULL)
111 {
112 EMSG2(_(e_notopen), fname);
113 return;
114 }
115 }
104 log_fd = file; 116 log_fd = file;
117
105 if (log_fd != NULL) 118 if (log_fd != NULL)
106 { 119 {
107 fprintf(log_fd, "==== start log session ====\n"); 120 fprintf(log_fd, "==== start log session ====\n");
108 #ifdef FEAT_RELTIME 121 #ifdef FEAT_RELTIME
109 profile_start(&log_start); 122 profile_start(&log_start);
358 * Close a channel and free all its resources if there is no further action 371 * Close a channel and free all its resources if there is no further action
359 * possible, there is no callback to be invoked or the associated job was 372 * possible, there is no callback to be invoked or the associated job was
360 * killed. 373 * killed.
361 * Return TRUE if the channel was freed. 374 * Return TRUE if the channel was freed.
362 */ 375 */
363 int 376 static int
364 channel_may_free(channel_T *channel) 377 channel_may_free(channel_T *channel)
365 { 378 {
366 if (!channel_still_useful(channel)) 379 if (!channel_still_useful(channel))
367 { 380 {
368 channel_free(channel); 381 channel_free(channel);
369 return TRUE; 382 return TRUE;
370 } 383 }
384 return FALSE;
385 }
386
387 /*
388 * Decrement the reference count on "channel" and maybe free it when it goes
389 * down to zero. Don't free it if there is a pending action.
390 * Returns TRUE when the channel is no longer referenced.
391 */
392 int
393 channel_unref(channel_T *channel)
394 {
395 if (channel != NULL && --channel->ch_refcount <= 0)
396 return channel_may_free(channel);
371 return FALSE; 397 return FALSE;
372 } 398 }
373 399
374 /* 400 /*
375 * Close a channel and free all its resources. 401 * Close a channel and free all its resources.
815 841
816 #ifdef FEAT_GUI 842 #ifdef FEAT_GUI
817 channel_gui_register_one(channel, PART_SOCK); 843 channel_gui_register_one(channel, PART_SOCK);
818 #endif 844 #endif
819 845
846 return channel;
847 }
848
849 /*
850 * Implements ch_open().
851 */
852 channel_T *
853 channel_open_func(typval_T *argvars)
854 {
855 char_u *address;
856 char_u *p;
857 char *rest;
858 int port;
859 jobopt_T opt;
860 channel_T *channel;
861
862 address = get_tv_string(&argvars[0]);
863 if (argvars[1].v_type != VAR_UNKNOWN
864 && (argvars[1].v_type != VAR_DICT || argvars[1].vval.v_dict == NULL))
865 {
866 EMSG(_(e_invarg));
867 return NULL;
868 }
869
870 /* parse address */
871 p = vim_strchr(address, ':');
872 if (p == NULL)
873 {
874 EMSG2(_(e_invarg2), address);
875 return NULL;
876 }
877 *p++ = NUL;
878 port = strtol((char *)p, &rest, 10);
879 if (*address == NUL || port <= 0 || *rest != NUL)
880 {
881 p[-1] = ':';
882 EMSG2(_(e_invarg2), address);
883 return NULL;
884 }
885
886 /* parse options */
887 clear_job_options(&opt);
888 opt.jo_mode = MODE_JSON;
889 opt.jo_timeout = 2000;
890 if (get_job_options(&argvars[1], &opt,
891 JO_MODE_ALL + JO_CB_ALL + JO_WAITTIME + JO_TIMEOUT_ALL) == FAIL)
892 return NULL;
893 if (opt.jo_timeout < 0)
894 {
895 EMSG(_(e_invarg));
896 return NULL;
897 }
898
899 channel = channel_open((char *)address, port, opt.jo_waittime, NULL);
900 if (channel != NULL)
901 {
902 opt.jo_set = JO_ALL;
903 channel_set_options(channel, &opt);
904 }
820 return channel; 905 return channel;
821 } 906 }
822 907
823 static void 908 static void
824 may_close_part(sock_T *fd) 909 may_close_part(sock_T *fd)
2305 } 2390 }
2306 channel->ch_part[part].ch_block_id = 0; 2391 channel->ch_part[part].ch_block_id = 0;
2307 return FAIL; 2392 return FAIL;
2308 } 2393 }
2309 2394
2395 /*
2396 * Common for ch_read() and ch_readraw().
2397 */
2398 void
2399 common_channel_read(typval_T *argvars, typval_T *rettv, int raw)
2400 {
2401 channel_T *channel;
2402 int part;
2403 jobopt_T opt;
2404 int mode;
2405 int timeout;
2406 int id = -1;
2407 typval_T *listtv = NULL;
2408
2409 /* return an empty string by default */
2410 rettv->v_type = VAR_STRING;
2411 rettv->vval.v_string = NULL;
2412
2413 clear_job_options(&opt);
2414 if (get_job_options(&argvars[1], &opt, JO_TIMEOUT + JO_PART + JO_ID)
2415 == FAIL)
2416 return;
2417
2418 channel = get_channel_arg(&argvars[0], TRUE);
2419 if (channel != NULL)
2420 {
2421 if (opt.jo_set & JO_PART)
2422 part = opt.jo_part;
2423 else
2424 part = channel_part_read(channel);
2425 mode = channel_get_mode(channel, part);
2426 timeout = channel_get_timeout(channel, part);
2427 if (opt.jo_set & JO_TIMEOUT)
2428 timeout = opt.jo_timeout;
2429
2430 if (raw || mode == MODE_RAW || mode == MODE_NL)
2431 rettv->vval.v_string = channel_read_block(channel, part, timeout);
2432 else
2433 {
2434 if (opt.jo_set & JO_ID)
2435 id = opt.jo_id;
2436 channel_read_json_block(channel, part, timeout, id, &listtv);
2437 if (listtv != NULL)
2438 {
2439 *rettv = *listtv;
2440 vim_free(listtv);
2441 }
2442 else
2443 {
2444 rettv->v_type = VAR_SPECIAL;
2445 rettv->vval.v_number = VVAL_NONE;
2446 }
2447 }
2448 }
2449 }
2450
2310 # if defined(WIN32) || defined(FEAT_GUI_X11) || defined(FEAT_GUI_GTK) \ 2451 # if defined(WIN32) || defined(FEAT_GUI_X11) || defined(FEAT_GUI_GTK) \
2311 || defined(PROTO) 2452 || defined(PROTO)
2312 /* 2453 /*
2313 * Lookup the channel from the socket. Set "partp" to the fd index. 2454 * Lookup the channel from the socket. Set "partp" to the fd index.
2314 * Returns NULL when the socket isn't found. 2455 * Returns NULL when the socket isn't found.
2408 return FAIL; 2549 return FAIL;
2409 } 2550 }
2410 2551
2411 channel->ch_error = FALSE; 2552 channel->ch_error = FALSE;
2412 return OK; 2553 return OK;
2554 }
2555
2556 /*
2557 * Common for "ch_sendexpr()" and "ch_sendraw()".
2558 * Returns the channel if the caller should read the response.
2559 * Sets "part_read" to the the read fd.
2560 * Otherwise returns NULL.
2561 */
2562 channel_T *
2563 send_common(
2564 typval_T *argvars,
2565 char_u *text,
2566 int id,
2567 int eval,
2568 jobopt_T *opt,
2569 char *fun,
2570 int *part_read)
2571 {
2572 channel_T *channel;
2573 int part_send;
2574
2575 channel = get_channel_arg(&argvars[0], TRUE);
2576 if (channel == NULL)
2577 return NULL;
2578 part_send = channel_part_send(channel);
2579 *part_read = channel_part_read(channel);
2580
2581 clear_job_options(opt);
2582 if (get_job_options(&argvars[2], opt, JO_CALLBACK + JO_TIMEOUT) == FAIL)
2583 return NULL;
2584
2585 /* Set the callback. An empty callback means no callback and not reading
2586 * the response. With "ch_evalexpr()" and "ch_evalraw()" a callback is not
2587 * allowed. */
2588 if (opt->jo_callback != NULL && *opt->jo_callback != NUL)
2589 {
2590 if (eval)
2591 {
2592 EMSG2(_("E917: Cannot use a callback with %s()"), fun);
2593 return NULL;
2594 }
2595 channel_set_req_callback(channel, part_send, opt->jo_callback, id);
2596 }
2597
2598 if (channel_send(channel, part_send, text, fun) == OK
2599 && opt->jo_callback == NULL)
2600 return channel;
2601 return NULL;
2602 }
2603
2604 /*
2605 * common for "ch_evalexpr()" and "ch_sendexpr()"
2606 */
2607 void
2608 ch_expr_common(typval_T *argvars, typval_T *rettv, int eval)
2609 {
2610 char_u *text;
2611 typval_T *listtv;
2612 channel_T *channel;
2613 int id;
2614 ch_mode_T ch_mode;
2615 int part_send;
2616 int part_read;
2617 jobopt_T opt;
2618 int timeout;
2619
2620 /* return an empty string by default */
2621 rettv->v_type = VAR_STRING;
2622 rettv->vval.v_string = NULL;
2623
2624 channel = get_channel_arg(&argvars[0], TRUE);
2625 if (channel == NULL)
2626 return;
2627 part_send = channel_part_send(channel);
2628
2629 ch_mode = channel_get_mode(channel, part_send);
2630 if (ch_mode == MODE_RAW || ch_mode == MODE_NL)
2631 {
2632 EMSG(_("E912: cannot use ch_evalexpr()/ch_sendexpr() with a raw or nl channel"));
2633 return;
2634 }
2635
2636 id = channel_get_id();
2637 text = json_encode_nr_expr(id, &argvars[1],
2638 ch_mode == MODE_JS ? JSON_JS : 0);
2639 if (text == NULL)
2640 return;
2641
2642 channel = send_common(argvars, text, id, eval, &opt,
2643 eval ? "ch_evalexpr" : "ch_sendexpr", &part_read);
2644 vim_free(text);
2645 if (channel != NULL && eval)
2646 {
2647 if (opt.jo_set & JO_TIMEOUT)
2648 timeout = opt.jo_timeout;
2649 else
2650 timeout = channel_get_timeout(channel, part_read);
2651 timeout = channel_get_timeout(channel, part_read);
2652 if (channel_read_json_block(channel, part_read, timeout, id, &listtv)
2653 == OK)
2654 {
2655 list_T *list = listtv->vval.v_list;
2656
2657 /* Move the item from the list and then change the type to
2658 * avoid the value being freed. */
2659 *rettv = list->lv_last->li_tv;
2660 list->lv_last->li_tv.v_type = VAR_NUMBER;
2661 free_tv(listtv);
2662 }
2663 }
2664 }
2665
2666 /*
2667 * common for "ch_evalraw()" and "ch_sendraw()"
2668 */
2669 void
2670 ch_raw_common(typval_T *argvars, typval_T *rettv, int eval)
2671 {
2672 char_u buf[NUMBUFLEN];
2673 char_u *text;
2674 channel_T *channel;
2675 int part_read;
2676 jobopt_T opt;
2677 int timeout;
2678
2679 /* return an empty string by default */
2680 rettv->v_type = VAR_STRING;
2681 rettv->vval.v_string = NULL;
2682
2683 text = get_tv_string_buf(&argvars[1], buf);
2684 channel = send_common(argvars, text, 0, eval, &opt,
2685 eval ? "ch_evalraw" : "ch_sendraw", &part_read);
2686 if (channel != NULL && eval)
2687 {
2688 if (opt.jo_set & JO_TIMEOUT)
2689 timeout = opt.jo_timeout;
2690 else
2691 timeout = channel_get_timeout(channel, part_read);
2692 rettv->vval.v_string = channel_read_block(channel, part_read, timeout);
2693 }
2413 } 2694 }
2414 2695
2415 # if (defined(UNIX) && !defined(HAVE_SELECT)) || defined(PROTO) 2696 # if (defined(UNIX) && !defined(HAVE_SELECT)) || defined(PROTO)
2416 /* 2697 /*
2417 * Add open channels to the poll struct. 2698 * Add open channels to the poll struct.
2693 channel_get_timeout(channel_T *channel, int part) 2974 channel_get_timeout(channel_T *channel, int part)
2694 { 2975 {
2695 return channel->ch_part[part].ch_timeout; 2976 return channel->ch_part[part].ch_timeout;
2696 } 2977 }
2697 2978
2979 /*
2980 * Get a callback from "arg". It can be a Funcref or a function name.
2981 * When "arg" is zero return an empty string.
2982 * Return NULL for an invalid argument.
2983 */
2984 static char_u *
2985 get_callback(typval_T *arg)
2986 {
2987 if (arg->v_type == VAR_FUNC || arg->v_type == VAR_STRING)
2988 return arg->vval.v_string;
2989 if (arg->v_type == VAR_NUMBER && arg->vval.v_number == 0)
2990 return (char_u *)"";
2991 EMSG(_("E999: Invalid callback argument"));
2992 return NULL;
2993 }
2994
2995 static int
2996 handle_mode(typval_T *item, jobopt_T *opt, ch_mode_T *modep, int jo)
2997 {
2998 char_u *val = get_tv_string(item);
2999
3000 opt->jo_set |= jo;
3001 if (STRCMP(val, "nl") == 0)
3002 *modep = MODE_NL;
3003 else if (STRCMP(val, "raw") == 0)
3004 *modep = MODE_RAW;
3005 else if (STRCMP(val, "js") == 0)
3006 *modep = MODE_JS;
3007 else if (STRCMP(val, "json") == 0)
3008 *modep = MODE_JSON;
3009 else
3010 {
3011 EMSG2(_(e_invarg2), val);
3012 return FAIL;
3013 }
3014 return OK;
3015 }
3016
3017 static int
3018 handle_io(typval_T *item, int part, jobopt_T *opt)
3019 {
3020 char_u *val = get_tv_string(item);
3021
3022 opt->jo_set |= JO_OUT_IO << (part - PART_OUT);
3023 if (STRCMP(val, "null") == 0)
3024 opt->jo_io[part] = JIO_NULL;
3025 else if (STRCMP(val, "pipe") == 0)
3026 opt->jo_io[part] = JIO_PIPE;
3027 else if (STRCMP(val, "file") == 0)
3028 opt->jo_io[part] = JIO_FILE;
3029 else if (STRCMP(val, "buffer") == 0)
3030 opt->jo_io[part] = JIO_BUFFER;
3031 else if (STRCMP(val, "out") == 0 && part == PART_ERR)
3032 opt->jo_io[part] = JIO_OUT;
3033 else
3034 {
3035 EMSG2(_(e_invarg2), val);
3036 return FAIL;
3037 }
3038 return OK;
3039 }
3040
3041 void
3042 clear_job_options(jobopt_T *opt)
3043 {
3044 vim_memset(opt, 0, sizeof(jobopt_T));
3045 }
3046
3047 /*
3048 * Get the PART_ number from the first character of an option name.
3049 */
3050 static int
3051 part_from_char(int c)
3052 {
3053 return c == 'i' ? PART_IN : c == 'o' ? PART_OUT: PART_ERR;
3054 }
3055
3056 /*
3057 * Get the option entries from the dict in "tv", parse them and put the result
3058 * in "opt".
3059 * Only accept options in "supported".
3060 * If an option value is invalid return FAIL.
3061 */
3062 int
3063 get_job_options(typval_T *tv, jobopt_T *opt, int supported)
3064 {
3065 typval_T *item;
3066 char_u *val;
3067 dict_T *dict;
3068 int todo;
3069 hashitem_T *hi;
3070 int part;
3071
3072 opt->jo_set = 0;
3073 if (tv->v_type == VAR_UNKNOWN)
3074 return OK;
3075 if (tv->v_type != VAR_DICT)
3076 {
3077 EMSG(_(e_invarg));
3078 return FAIL;
3079 }
3080 dict = tv->vval.v_dict;
3081 if (dict == NULL)
3082 return OK;
3083
3084 todo = (int)dict->dv_hashtab.ht_used;
3085 for (hi = dict->dv_hashtab.ht_array; todo > 0; ++hi)
3086 if (!HASHITEM_EMPTY(hi))
3087 {
3088 item = &dict_lookup(hi)->di_tv;
3089
3090 if (STRCMP(hi->hi_key, "mode") == 0)
3091 {
3092 if (!(supported & JO_MODE))
3093 break;
3094 if (handle_mode(item, opt, &opt->jo_mode, JO_MODE) == FAIL)
3095 return FAIL;
3096 }
3097 else if (STRCMP(hi->hi_key, "in-mode") == 0)
3098 {
3099 if (!(supported & JO_IN_MODE))
3100 break;
3101 if (handle_mode(item, opt, &opt->jo_in_mode, JO_IN_MODE)
3102 == FAIL)
3103 return FAIL;
3104 }
3105 else if (STRCMP(hi->hi_key, "out-mode") == 0)
3106 {
3107 if (!(supported & JO_OUT_MODE))
3108 break;
3109 if (handle_mode(item, opt, &opt->jo_out_mode, JO_OUT_MODE)
3110 == FAIL)
3111 return FAIL;
3112 }
3113 else if (STRCMP(hi->hi_key, "err-mode") == 0)
3114 {
3115 if (!(supported & JO_ERR_MODE))
3116 break;
3117 if (handle_mode(item, opt, &opt->jo_err_mode, JO_ERR_MODE)
3118 == FAIL)
3119 return FAIL;
3120 }
3121 else if (STRCMP(hi->hi_key, "in-io") == 0
3122 || STRCMP(hi->hi_key, "out-io") == 0
3123 || STRCMP(hi->hi_key, "err-io") == 0)
3124 {
3125 if (!(supported & JO_OUT_IO))
3126 break;
3127 if (handle_io(item, part_from_char(*hi->hi_key), opt) == FAIL)
3128 return FAIL;
3129 }
3130 else if (STRCMP(hi->hi_key, "in-name") == 0
3131 || STRCMP(hi->hi_key, "out-name") == 0
3132 || STRCMP(hi->hi_key, "err-name") == 0)
3133 {
3134 part = part_from_char(*hi->hi_key);
3135
3136 if (!(supported & JO_OUT_IO))
3137 break;
3138 opt->jo_set |= JO_OUT_NAME << (part - PART_OUT);
3139 opt->jo_io_name[part] =
3140 get_tv_string_buf_chk(item, opt->jo_io_name_buf[part]);
3141 }
3142 else if (STRCMP(hi->hi_key, "in-buf") == 0
3143 || STRCMP(hi->hi_key, "out-buf") == 0
3144 || STRCMP(hi->hi_key, "err-buf") == 0)
3145 {
3146 part = part_from_char(*hi->hi_key);
3147
3148 if (!(supported & JO_OUT_IO))
3149 break;
3150 opt->jo_set |= JO_OUT_BUF << (part - PART_OUT);
3151 opt->jo_io_buf[part] = get_tv_number(item);
3152 if (opt->jo_io_buf[part] <= 0)
3153 {
3154 EMSG2(_(e_invarg2), get_tv_string(item));
3155 return FAIL;
3156 }
3157 if (buflist_findnr(opt->jo_io_buf[part]) == NULL)
3158 {
3159 EMSGN(_(e_nobufnr), (long)opt->jo_io_buf[part]);
3160 return FAIL;
3161 }
3162 }
3163 else if (STRCMP(hi->hi_key, "in-top") == 0
3164 || STRCMP(hi->hi_key, "in-bot") == 0)
3165 {
3166 linenr_T *lp;
3167
3168 if (!(supported & JO_OUT_IO))
3169 break;
3170 if (hi->hi_key[3] == 't')
3171 {
3172 lp = &opt->jo_in_top;
3173 opt->jo_set |= JO_IN_TOP;
3174 }
3175 else
3176 {
3177 lp = &opt->jo_in_bot;
3178 opt->jo_set |= JO_IN_BOT;
3179 }
3180 *lp = get_tv_number(item);
3181 if (*lp < 0)
3182 {
3183 EMSG2(_(e_invarg2), get_tv_string(item));
3184 return FAIL;
3185 }
3186 }
3187 else if (STRCMP(hi->hi_key, "channel") == 0)
3188 {
3189 if (!(supported & JO_OUT_IO))
3190 break;
3191 opt->jo_set |= JO_CHANNEL;
3192 if (item->v_type != VAR_CHANNEL)
3193 {
3194 EMSG2(_(e_invarg2), "channel");
3195 return FAIL;
3196 }
3197 opt->jo_channel = item->vval.v_channel;
3198 }
3199 else if (STRCMP(hi->hi_key, "callback") == 0)
3200 {
3201 if (!(supported & JO_CALLBACK))
3202 break;
3203 opt->jo_set |= JO_CALLBACK;
3204 opt->jo_callback = get_callback(item);
3205 if (opt->jo_callback == NULL)
3206 {
3207 EMSG2(_(e_invarg2), "callback");
3208 return FAIL;
3209 }
3210 }
3211 else if (STRCMP(hi->hi_key, "out-cb") == 0)
3212 {
3213 if (!(supported & JO_OUT_CALLBACK))
3214 break;
3215 opt->jo_set |= JO_OUT_CALLBACK;
3216 opt->jo_out_cb = get_callback(item);
3217 if (opt->jo_out_cb == NULL)
3218 {
3219 EMSG2(_(e_invarg2), "out-cb");
3220 return FAIL;
3221 }
3222 }
3223 else if (STRCMP(hi->hi_key, "err-cb") == 0)
3224 {
3225 if (!(supported & JO_ERR_CALLBACK))
3226 break;
3227 opt->jo_set |= JO_ERR_CALLBACK;
3228 opt->jo_err_cb = get_callback(item);
3229 if (opt->jo_err_cb == NULL)
3230 {
3231 EMSG2(_(e_invarg2), "err-cb");
3232 return FAIL;
3233 }
3234 }
3235 else if (STRCMP(hi->hi_key, "close-cb") == 0)
3236 {
3237 if (!(supported & JO_CLOSE_CALLBACK))
3238 break;
3239 opt->jo_set |= JO_CLOSE_CALLBACK;
3240 opt->jo_close_cb = get_callback(item);
3241 if (opt->jo_close_cb == NULL)
3242 {
3243 EMSG2(_(e_invarg2), "close-cb");
3244 return FAIL;
3245 }
3246 }
3247 else if (STRCMP(hi->hi_key, "waittime") == 0)
3248 {
3249 if (!(supported & JO_WAITTIME))
3250 break;
3251 opt->jo_set |= JO_WAITTIME;
3252 opt->jo_waittime = get_tv_number(item);
3253 }
3254 else if (STRCMP(hi->hi_key, "timeout") == 0)
3255 {
3256 if (!(supported & JO_TIMEOUT))
3257 break;
3258 opt->jo_set |= JO_TIMEOUT;
3259 opt->jo_timeout = get_tv_number(item);
3260 }
3261 else if (STRCMP(hi->hi_key, "out-timeout") == 0)
3262 {
3263 if (!(supported & JO_OUT_TIMEOUT))
3264 break;
3265 opt->jo_set |= JO_OUT_TIMEOUT;
3266 opt->jo_out_timeout = get_tv_number(item);
3267 }
3268 else if (STRCMP(hi->hi_key, "err-timeout") == 0)
3269 {
3270 if (!(supported & JO_ERR_TIMEOUT))
3271 break;
3272 opt->jo_set |= JO_ERR_TIMEOUT;
3273 opt->jo_err_timeout = get_tv_number(item);
3274 }
3275 else if (STRCMP(hi->hi_key, "part") == 0)
3276 {
3277 if (!(supported & JO_PART))
3278 break;
3279 opt->jo_set |= JO_PART;
3280 val = get_tv_string(item);
3281 if (STRCMP(val, "err") == 0)
3282 opt->jo_part = PART_ERR;
3283 else
3284 {
3285 EMSG2(_(e_invarg2), val);
3286 return FAIL;
3287 }
3288 }
3289 else if (STRCMP(hi->hi_key, "id") == 0)
3290 {
3291 if (!(supported & JO_ID))
3292 break;
3293 opt->jo_set |= JO_ID;
3294 opt->jo_id = get_tv_number(item);
3295 }
3296 else if (STRCMP(hi->hi_key, "stoponexit") == 0)
3297 {
3298 if (!(supported & JO_STOPONEXIT))
3299 break;
3300 opt->jo_set |= JO_STOPONEXIT;
3301 opt->jo_stoponexit = get_tv_string_buf_chk(item,
3302 opt->jo_soe_buf);
3303 if (opt->jo_stoponexit == NULL)
3304 {
3305 EMSG2(_(e_invarg2), "stoponexit");
3306 return FAIL;
3307 }
3308 }
3309 else if (STRCMP(hi->hi_key, "exit-cb") == 0)
3310 {
3311 if (!(supported & JO_EXIT_CB))
3312 break;
3313 opt->jo_set |= JO_EXIT_CB;
3314 opt->jo_exit_cb = get_tv_string_buf_chk(item, opt->jo_ecb_buf);
3315 if (opt->jo_exit_cb == NULL)
3316 {
3317 EMSG2(_(e_invarg2), "exit-cb");
3318 return FAIL;
3319 }
3320 }
3321 else
3322 break;
3323 --todo;
3324 }
3325 if (todo > 0)
3326 {
3327 EMSG2(_(e_invarg2), hi->hi_key);
3328 return FAIL;
3329 }
3330
3331 return OK;
3332 }
3333
3334 /*
3335 * Get the channel from the argument.
3336 * Returns NULL if the handle is invalid.
3337 */
3338 channel_T *
3339 get_channel_arg(typval_T *tv, int check_open)
3340 {
3341 channel_T *channel = NULL;
3342
3343 if (tv->v_type == VAR_JOB)
3344 {
3345 if (tv->vval.v_job != NULL)
3346 channel = tv->vval.v_job->jv_channel;
3347 }
3348 else if (tv->v_type == VAR_CHANNEL)
3349 {
3350 channel = tv->vval.v_channel;
3351 }
3352 else
3353 {
3354 EMSG2(_(e_invarg2), get_tv_string(tv));
3355 return NULL;
3356 }
3357
3358 if (check_open && (channel == NULL || !channel_is_open(channel)))
3359 {
3360 EMSG(_("E906: not an open channel"));
3361 return NULL;
3362 }
3363 return channel;
3364 }
3365
3366 static job_T *first_job = NULL;
3367
3368 static void
3369 job_free(job_T *job)
3370 {
3371 ch_log(job->jv_channel, "Freeing job");
3372 if (job->jv_channel != NULL)
3373 {
3374 /* The link from the channel to the job doesn't count as a reference,
3375 * thus don't decrement the refcount of the job. The reference from
3376 * the job to the channel does count the refrence, decrement it and
3377 * NULL the reference. We don't set ch_job_killed, unreferencing the
3378 * job doesn't mean it stops running. */
3379 job->jv_channel->ch_job = NULL;
3380 channel_unref(job->jv_channel);
3381 }
3382 mch_clear_job(job);
3383
3384 if (job->jv_next != NULL)
3385 job->jv_next->jv_prev = job->jv_prev;
3386 if (job->jv_prev == NULL)
3387 first_job = job->jv_next;
3388 else
3389 job->jv_prev->jv_next = job->jv_next;
3390
3391 vim_free(job->jv_stoponexit);
3392 vim_free(job->jv_exit_cb);
3393 vim_free(job);
3394 }
3395
3396 void
3397 job_unref(job_T *job)
3398 {
3399 if (job != NULL && --job->jv_refcount <= 0)
3400 {
3401 /* Do not free the job when it has not ended yet and there is a
3402 * "stoponexit" flag or an exit callback. */
3403 if (job->jv_status != JOB_STARTED
3404 || (job->jv_stoponexit == NULL && job->jv_exit_cb == NULL))
3405 {
3406 job_free(job);
3407 }
3408 else if (job->jv_channel != NULL)
3409 {
3410 /* Do remove the link to the channel, otherwise it hangs
3411 * around until Vim exits. See job_free() for refcount. */
3412 job->jv_channel->ch_job = NULL;
3413 channel_unref(job->jv_channel);
3414 job->jv_channel = NULL;
3415 }
3416 }
3417 }
3418
3419 /*
3420 * Allocate a job. Sets the refcount to one and sets options default.
3421 */
3422 static job_T *
3423 job_alloc(void)
3424 {
3425 job_T *job;
3426
3427 job = (job_T *)alloc_clear(sizeof(job_T));
3428 if (job != NULL)
3429 {
3430 job->jv_refcount = 1;
3431 job->jv_stoponexit = vim_strsave((char_u *)"term");
3432
3433 if (first_job != NULL)
3434 {
3435 first_job->jv_prev = job;
3436 job->jv_next = first_job;
3437 }
3438 first_job = job;
3439 }
3440 return job;
3441 }
3442
3443 void
3444 job_set_options(job_T *job, jobopt_T *opt)
3445 {
3446 if (opt->jo_set & JO_STOPONEXIT)
3447 {
3448 vim_free(job->jv_stoponexit);
3449 if (opt->jo_stoponexit == NULL || *opt->jo_stoponexit == NUL)
3450 job->jv_stoponexit = NULL;
3451 else
3452 job->jv_stoponexit = vim_strsave(opt->jo_stoponexit);
3453 }
3454 if (opt->jo_set & JO_EXIT_CB)
3455 {
3456 vim_free(job->jv_exit_cb);
3457 if (opt->jo_exit_cb == NULL || *opt->jo_exit_cb == NUL)
3458 job->jv_exit_cb = NULL;
3459 else
3460 job->jv_exit_cb = vim_strsave(opt->jo_exit_cb);
3461 }
3462 }
3463
3464 /*
3465 * Called when Vim is exiting: kill all jobs that have the "stoponexit" flag.
3466 */
3467 void
3468 job_stop_on_exit()
3469 {
3470 job_T *job;
3471
3472 for (job = first_job; job != NULL; job = job->jv_next)
3473 if (job->jv_status == JOB_STARTED && job->jv_stoponexit != NULL)
3474 mch_stop_job(job, job->jv_stoponexit);
3475 }
3476
3477 /*
3478 * Called once in a while: check if any jobs with an "exit-cb" have ended.
3479 */
3480 void
3481 job_check_ended(void)
3482 {
3483 static time_t last_check = 0;
3484 time_t now;
3485 job_T *job;
3486 job_T *next;
3487
3488 /* Only do this once in 10 seconds. */
3489 now = time(NULL);
3490 if (last_check + 10 < now)
3491 {
3492 last_check = now;
3493 for (job = first_job; job != NULL; job = next)
3494 {
3495 next = job->jv_next;
3496 if (job->jv_status == JOB_STARTED && job->jv_exit_cb != NULL)
3497 job_status(job); /* may free "job" */
3498 }
3499 }
3500 }
3501
3502 /*
3503 * "job_start()" function
3504 */
3505 job_T *
3506 job_start(typval_T *argvars)
3507 {
3508 job_T *job;
3509 char_u *cmd = NULL;
3510 #if defined(UNIX)
3511 # define USE_ARGV
3512 char **argv = NULL;
3513 int argc = 0;
3514 #else
3515 garray_T ga;
3516 #endif
3517 jobopt_T opt;
3518 int part;
3519
3520 job = job_alloc();
3521 if (job == NULL)
3522 return NULL;
3523
3524 job->jv_status = JOB_FAILED;
3525
3526 /* Default mode is NL. */
3527 clear_job_options(&opt);
3528 opt.jo_mode = MODE_NL;
3529 if (get_job_options(&argvars[1], &opt,
3530 JO_MODE_ALL + JO_CB_ALL + JO_TIMEOUT_ALL
3531 + JO_STOPONEXIT + JO_EXIT_CB + JO_OUT_IO) == FAIL)
3532 return job;
3533
3534 /* Check that when io is "file" that there is a file name. */
3535 for (part = PART_OUT; part <= PART_IN; ++part)
3536 if ((opt.jo_set & (JO_OUT_IO << (part - PART_OUT)))
3537 && opt.jo_io[part] == JIO_FILE
3538 && (!(opt.jo_set & (JO_OUT_NAME << (part - PART_OUT)))
3539 || *opt.jo_io_name[part] == NUL))
3540 {
3541 EMSG(_("E920: -io file requires -name to be set"));
3542 return job;
3543 }
3544
3545 if ((opt.jo_set & JO_IN_IO) && opt.jo_io[PART_IN] == JIO_BUFFER)
3546 {
3547 buf_T *buf = NULL;
3548
3549 /* check that we can find the buffer before starting the job */
3550 if (opt.jo_set & JO_IN_BUF)
3551 {
3552 buf = buflist_findnr(opt.jo_io_buf[PART_IN]);
3553 if (buf == NULL)
3554 EMSGN(_(e_nobufnr), (long)opt.jo_io_buf[PART_IN]);
3555 }
3556 else if (!(opt.jo_set & JO_IN_NAME))
3557 {
3558 EMSG(_("E915: in-io buffer requires in-buf or in-name to be set"));
3559 }
3560 else
3561 buf = buflist_find_by_name(opt.jo_io_name[PART_IN], FALSE);
3562 if (buf == NULL)
3563 return job;
3564 if (buf->b_ml.ml_mfp == NULL)
3565 {
3566 char_u numbuf[NUMBUFLEN];
3567 char_u *s;
3568
3569 if (opt.jo_set & JO_IN_BUF)
3570 {
3571 sprintf((char *)numbuf, "%d", opt.jo_io_buf[PART_IN]);
3572 s = numbuf;
3573 }
3574 else
3575 s = opt.jo_io_name[PART_IN];
3576 EMSG2(_("E918: buffer must be loaded: %s"), s);
3577 return job;
3578 }
3579 job->jv_in_buf = buf;
3580 }
3581
3582 job_set_options(job, &opt);
3583
3584 #ifndef USE_ARGV
3585 ga_init2(&ga, (int)sizeof(char*), 20);
3586 #endif
3587
3588 if (argvars[0].v_type == VAR_STRING)
3589 {
3590 /* Command is a string. */
3591 cmd = argvars[0].vval.v_string;
3592 #ifdef USE_ARGV
3593 if (mch_parse_cmd(cmd, FALSE, &argv, &argc) == FAIL)
3594 return job;
3595 argv[argc] = NULL;
3596 #endif
3597 }
3598 else if (argvars[0].v_type != VAR_LIST
3599 || argvars[0].vval.v_list == NULL
3600 || argvars[0].vval.v_list->lv_len < 1)
3601 {
3602 EMSG(_(e_invarg));
3603 return job;
3604 }
3605 else
3606 {
3607 list_T *l = argvars[0].vval.v_list;
3608 listitem_T *li;
3609 char_u *s;
3610
3611 #ifdef USE_ARGV
3612 /* Pass argv[] to mch_call_shell(). */
3613 argv = (char **)alloc(sizeof(char *) * (l->lv_len + 1));
3614 if (argv == NULL)
3615 return job;
3616 #endif
3617 for (li = l->lv_first; li != NULL; li = li->li_next)
3618 {
3619 s = get_tv_string_chk(&li->li_tv);
3620 if (s == NULL)
3621 goto theend;
3622 #ifdef USE_ARGV
3623 argv[argc++] = (char *)s;
3624 #else
3625 /* Only escape when needed, double quotes are not always allowed. */
3626 if (li != l->lv_first && vim_strpbrk(s, (char_u *)" \t\"") != NULL)
3627 {
3628 s = vim_strsave_shellescape(s, FALSE, TRUE);
3629 if (s == NULL)
3630 goto theend;
3631 ga_concat(&ga, s);
3632 vim_free(s);
3633 }
3634 else
3635 ga_concat(&ga, s);
3636 if (li->li_next != NULL)
3637 ga_append(&ga, ' ');
3638 #endif
3639 }
3640 #ifdef USE_ARGV
3641 argv[argc] = NULL;
3642 #else
3643 cmd = ga.ga_data;
3644 #endif
3645 }
3646
3647 #ifdef USE_ARGV
3648 if (ch_log_active())
3649 {
3650 garray_T ga;
3651 int i;
3652
3653 ga_init2(&ga, (int)sizeof(char), 200);
3654 for (i = 0; i < argc; ++i)
3655 {
3656 if (i > 0)
3657 ga_concat(&ga, (char_u *)" ");
3658 ga_concat(&ga, (char_u *)argv[i]);
3659 }
3660 ch_logs(NULL, "Starting job: %s", (char *)ga.ga_data);
3661 ga_clear(&ga);
3662 }
3663 mch_start_job(argv, job, &opt);
3664 #else
3665 ch_logs(NULL, "Starting job: %s", (char *)cmd);
3666 mch_start_job((char *)cmd, job, &opt);
3667 #endif
3668
3669 /* If the channel is reading from a buffer, write lines now. */
3670 if (job->jv_channel != NULL)
3671 channel_write_in(job->jv_channel);
3672
3673 theend:
3674 #ifdef USE_ARGV
3675 vim_free(argv);
3676 #else
3677 vim_free(ga.ga_data);
3678 #endif
3679 return job;
3680 }
3681
3682 /*
3683 * Get the status of "job" and invoke the exit callback when needed.
3684 * The returned string is not allocated.
3685 */
3686 char *
3687 job_status(job_T *job)
3688 {
3689 char *result;
3690
3691 if (job->jv_status == JOB_ENDED)
3692 /* No need to check, dead is dead. */
3693 result = "dead";
3694 else if (job->jv_status == JOB_FAILED)
3695 result = "fail";
3696 else
3697 {
3698 result = mch_job_status(job);
3699 if (job->jv_status == JOB_ENDED)
3700 ch_log(job->jv_channel, "Job ended");
3701 if (job->jv_status == JOB_ENDED && job->jv_exit_cb != NULL)
3702 {
3703 typval_T argv[3];
3704 typval_T rettv;
3705 int dummy;
3706
3707 /* invoke the exit callback; make sure the refcount is > 0 */
3708 ++job->jv_refcount;
3709 argv[0].v_type = VAR_JOB;
3710 argv[0].vval.v_job = job;
3711 argv[1].v_type = VAR_NUMBER;
3712 argv[1].vval.v_number = job->jv_exitval;
3713 call_func(job->jv_exit_cb, (int)STRLEN(job->jv_exit_cb),
3714 &rettv, 2, argv, 0L, 0L, &dummy, TRUE, NULL);
3715 clear_tv(&rettv);
3716 --job->jv_refcount;
3717 }
3718 if (job->jv_status == JOB_ENDED && job->jv_refcount == 0)
3719 {
3720 /* The job was already unreferenced, now that it ended it can be
3721 * freed. Careful: caller must not use "job" after this! */
3722 job_free(job);
3723 }
3724 }
3725 return result;
3726 }
3727
3728 int
3729 job_stop(job_T *job, typval_T *argvars)
3730 {
3731 char_u *arg;
3732
3733 if (argvars[1].v_type == VAR_UNKNOWN)
3734 arg = (char_u *)"";
3735 else
3736 {
3737 arg = get_tv_string_chk(&argvars[1]);
3738 if (arg == NULL)
3739 {
3740 EMSG(_(e_invarg));
3741 return 0;
3742 }
3743 }
3744 ch_logs(job->jv_channel, "Stopping job with '%s'", (char *)arg);
3745 if (mch_stop_job(job, arg) == FAIL)
3746 return 0;
3747
3748 /* Assume that "hup" does not kill the job. */
3749 if (job->jv_channel != NULL && STRCMP(arg, "hup") != 0)
3750 job->jv_channel->ch_job_killed = TRUE;
3751
3752 /* We don't try freeing the job, obviously the caller still has a
3753 * reference to it. */
3754 return 1;
3755 }
3756
2698 #endif /* FEAT_JOB_CHANNEL */ 3757 #endif /* FEAT_JOB_CHANNEL */