To: vim_dev@googlegroups.com Subject: Patch 7.4.1356 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 7.4.1356 Problem: Job and channel options parsing is scattered. Solution: Move all option value parsing to get_job_options(); Files: src/channel.c, src/eval.c, src/structs.h, src/proto/channel.pro, src/testdir/test_channel.vim *** ../vim-7.4.1355/src/channel.c 2016-02-19 21:04:57.896318285 +0100 --- src/channel.c 2016-02-19 22:05:41.829863314 +0100 *************** *** 749,772 **** } /* - * Set the mode of channel "channel" to "mode". - */ - void - channel_set_mode(channel_T *channel, ch_mode_T mode) - { - channel->ch_mode = mode; - } - - /* - * Set the read timeout of channel "channel". - */ - void - channel_set_timeout(channel_T *channel, int timeout) - { - channel->ch_timeout = timeout; - } - - /* * Set the callback for channel "channel". */ void --- 749,754 ---- *************** *** 782,790 **** void channel_set_options(channel_T *channel, jobopt_T *options) { ! channel_set_mode(channel, options->jo_mode); ! if (options->jo_callback != NULL && *options->jo_callback != NUL) channel_set_callback(channel, options->jo_callback); } --- 764,776 ---- void channel_set_options(channel_T *channel, jobopt_T *options) { ! if (options->jo_set & JO_MODE) ! channel->ch_mode = options->jo_mode; ! if (options->jo_set & JO_TIMEOUT) ! channel->ch_timeout = options->jo_timeout; ! if ((options->jo_set & JO_CALLBACK) ! && options->jo_callback != NULL && *options->jo_callback != NUL) channel_set_callback(channel, options->jo_callback); } *** ../vim-7.4.1355/src/eval.c 2016-02-19 21:04:57.900318243 +0100 --- src/eval.c 2016-02-19 22:29:48.730609433 +0100 *************** *** 510,515 **** --- 510,516 ---- static void f_ch_readraw(typval_T *argvars, typval_T *rettv); static void f_ch_sendexpr(typval_T *argvars, typval_T *rettv); static void f_ch_sendraw(typval_T *argvars, typval_T *rettv); + static void f_ch_setoptions(typval_T *argvars, typval_T *rettv); static void f_ch_status(typval_T *argvars, typval_T *rettv); #endif static void f_changenr(typval_T *argvars, typval_T *rettv); *************** *** 8131,8136 **** --- 8132,8138 ---- {"ch_readraw", 1, 2, f_ch_readraw}, {"ch_sendexpr", 2, 3, f_ch_sendexpr}, {"ch_sendraw", 2, 3, f_ch_sendraw}, + {"ch_setoptions", 2, 2, f_ch_setoptions}, {"ch_status", 1, 1, f_ch_status}, #endif {"changenr", 0, 0, f_changenr}, *************** *** 9870,9913 **** } /* ! * Get the option entries from "dict", and parse them. * If an option value is invalid return FAIL. */ static int ! get_job_options(dict_T *dict, jobopt_T *opt) { ! dictitem_T *item; char_u *mode; ! if (dict == NULL) return OK; ! ! if ((item = dict_find(dict, (char_u *)"mode", -1)) != NULL) { ! mode = get_tv_string(&item->di_tv); ! if (STRCMP(mode, "nl") == 0) ! opt->jo_mode = MODE_NL; ! else if (STRCMP(mode, "raw") == 0) ! opt->jo_mode = MODE_RAW; ! else if (STRCMP(mode, "js") == 0) ! opt->jo_mode = MODE_JS; ! else if (STRCMP(mode, "json") == 0) ! opt->jo_mode = MODE_JSON; ! else ! { ! EMSG2(_(e_invarg2), mode); ! return FAIL; ! } } ! if ((item = dict_find(dict, (char_u *)"callback", -1)) != NULL) ! { ! opt->jo_callback = get_callback(&item->di_tv); ! if (opt->jo_callback == NULL) { ! EMSG2(_(e_invarg2), "callback"); ! return FAIL; } } return OK; --- 9872,9962 ---- } /* ! * Get the option entries from the dict in "tv", parse them and put the result ! * in "opt". ! * Only accept options in "supported". * If an option value is invalid return FAIL. */ static int ! get_job_options(typval_T *tv, jobopt_T *opt, int supported) { ! typval_T *item; char_u *mode; + dict_T *dict; + int todo; + hashitem_T *hi; ! if (tv->v_type == VAR_UNKNOWN) return OK; ! if (tv->v_type != VAR_DICT) { ! EMSG(_(e_invarg)); ! return FAIL; } + dict = tv->vval.v_dict; + if (dict == NULL) + return OK; ! todo = (int)dict->dv_hashtab.ht_used; ! for (hi = dict->dv_hashtab.ht_array; todo > 0; ++hi) ! if (!HASHITEM_EMPTY(hi)) { ! item = &HI2DI(hi)->di_tv; ! ! if (STRCMP(hi->hi_key, "mode") == 0) ! { ! if (!(supported & JO_MODE)) ! break; ! opt->jo_set |= JO_MODE; ! mode = get_tv_string(item); ! if (STRCMP(mode, "nl") == 0) ! opt->jo_mode = MODE_NL; ! else if (STRCMP(mode, "raw") == 0) ! opt->jo_mode = MODE_RAW; ! else if (STRCMP(mode, "js") == 0) ! opt->jo_mode = MODE_JS; ! else if (STRCMP(mode, "json") == 0) ! opt->jo_mode = MODE_JSON; ! else ! { ! EMSG2(_(e_invarg2), mode); ! return FAIL; ! } ! } ! else if (STRCMP(hi->hi_key, "callback") == 0) ! { ! if (!(supported & JO_CALLBACK)) ! break; ! opt->jo_set |= JO_CALLBACK; ! opt->jo_callback = get_callback(item); ! if (opt->jo_callback == NULL) ! { ! EMSG2(_(e_invarg2), "callback"); ! return FAIL; ! } ! } ! else if (STRCMP(hi->hi_key, "waittime") == 0) ! { ! if (!(supported & JO_WAITTIME)) ! break; ! opt->jo_set |= JO_WAITTIME; ! opt->jo_waittime = get_tv_number(item); ! } ! else if (STRCMP(hi->hi_key, "timeout") == 0) ! { ! if (!(supported & JO_TIMEOUT)) ! break; ! opt->jo_set |= JO_TIMEOUT; ! opt->jo_timeout = get_tv_number(item); ! } ! else ! break; ! --todo; } + if (todo > 0) + { + EMSG2(_(e_invarg2), hi->hi_key); + return FAIL; } return OK; *************** *** 10002,10010 **** char_u *p; char *rest; int port; ! int waittime = 0; ! int timeout = 2000; ! jobopt_T options; channel_T *channel; /* default: fail */ --- 10051,10057 ---- char_u *p; char *rest; int port; ! jobopt_T opt; channel_T *channel; /* default: fail */ *************** *** 10035,10067 **** return; } ! options.jo_mode = MODE_JSON; ! options.jo_callback = NULL; ! if (argvars[1].v_type == VAR_DICT) ! { ! dict_T *dict = argvars[1].vval.v_dict; ! dictitem_T *item; ! ! /* parse argdict */ ! if (get_job_options(dict, &options) == FAIL) ! return; ! if ((item = dict_find(dict, (char_u *)"waittime", -1)) != NULL) ! waittime = get_tv_number(&item->di_tv); ! if ((item = dict_find(dict, (char_u *)"timeout", -1)) != NULL) ! timeout = get_tv_number(&item->di_tv); ! } ! if (timeout < 0) { EMSG(_(e_invarg)); return; } ! channel = channel_open((char *)address, port, waittime, NULL); if (channel != NULL) { rettv->vval.v_channel = channel; ! channel_set_options(channel, &options); ! channel_set_timeout(channel, timeout); } } --- 10082,10107 ---- return; } ! /* parse options */ ! opt.jo_mode = MODE_JSON; ! opt.jo_callback = NULL; ! opt.jo_waittime = 0; ! opt.jo_timeout = 2000; ! if (get_job_options(&argvars[1], &opt, ! JO_MODE + JO_CALLBACK + JO_WAITTIME + JO_TIMEOUT) == FAIL) ! return; ! if (opt.jo_timeout < 0) { EMSG(_(e_invarg)); return; } ! channel = channel_open((char *)address, port, opt.jo_waittime, NULL); if (channel != NULL) { rettv->vval.v_channel = channel; ! opt.jo_set = JO_ALL; ! channel_set_options(channel, &opt); } } *************** *** 10077,10107 **** rettv->v_type = VAR_STRING; rettv->vval.v_string = NULL; channel = get_channel_arg(&argvars[0]); if (channel != NULL) rettv->vval.v_string = channel_read_block(channel); } /* - * "ch_status()" function - */ - static void - f_ch_status(typval_T *argvars, typval_T *rettv) - { - /* return an empty string by default */ - rettv->v_type = VAR_STRING; - - if (argvars[0].v_type != VAR_CHANNEL) - { - EMSG2(_(e_invarg2), get_tv_string(&argvars[0])); - rettv->vval.v_string = NULL; - } - else - rettv->vval.v_string = vim_strsave( - (char_u *)channel_status(argvars[0].vval.v_channel)); - } - - /* * common for "sendexpr()" and "sendraw()" * Returns the channel if the caller should read the response. * Otherwise returns NULL. --- 10117,10130 ---- rettv->v_type = VAR_STRING; rettv->vval.v_string = NULL; + /* TODO: use timeout from the options */ + channel = get_channel_arg(&argvars[0]); if (channel != NULL) rettv->vval.v_string = channel_read_block(channel); } /* * common for "sendexpr()" and "sendraw()" * Returns the channel if the caller should read the response. * Otherwise returns NULL. *************** *** 10110,10140 **** send_common(typval_T *argvars, char_u *text, int id, char *fun) { channel_T *channel; ! char_u *callback = NULL; ! jobopt_T options; channel = get_channel_arg(&argvars[0]); if (channel == NULL) return NULL; ! if (argvars[2].v_type != VAR_UNKNOWN) ! { ! if (argvars[2].v_type != VAR_DICT) ! { ! EMSG(_(e_invarg)); ! return NULL; ! } ! options.jo_callback = NULL; ! if (get_job_options(argvars[2].vval.v_dict, &options) == FAIL) ! return NULL; ! callback = options.jo_callback; ! } /* Set the callback. An empty callback means no callback and not reading * the response. */ ! if (callback != NULL && *callback != NUL) ! channel_set_req_callback(channel, callback, id); ! if (channel_send(channel, text, fun) == OK && callback == NULL) return channel; return NULL; } --- 10133,10154 ---- send_common(typval_T *argvars, char_u *text, int id, char *fun) { channel_T *channel; ! jobopt_T opt; channel = get_channel_arg(&argvars[0]); if (channel == NULL) return NULL; ! opt.jo_callback = NULL; ! if (get_job_options(&argvars[2], &opt, JO_CALLBACK) == FAIL) ! return NULL; ! /* Set the callback. An empty callback means no callback and not reading * the response. */ ! if (opt.jo_callback != NULL && *opt.jo_callback != NUL) ! channel_set_req_callback(channel, opt.jo_callback, id); ! if (channel_send(channel, text, fun) == OK && opt.jo_callback == NULL) return channel; return NULL; } *************** *** 10208,10213 **** --- 10222,10263 ---- if (channel != NULL) rettv->vval.v_string = channel_read_block(channel); } + + /* + * "ch_setoptions()" function + */ + static void + f_ch_setoptions(typval_T *argvars, typval_T *rettv UNUSED) + { + channel_T *channel; + jobopt_T opt; + + channel = get_channel_arg(&argvars[0]); + if (channel == NULL) + return; + if (get_job_options(&argvars[1], &opt, JO_CALLBACK + JO_TIMEOUT) == FAIL) + return NULL; + channel_set_options(channel, &opt); + } + + /* + * "ch_status()" function + */ + static void + f_ch_status(typval_T *argvars, typval_T *rettv) + { + /* return an empty string by default */ + rettv->v_type = VAR_STRING; + + if (argvars[0].v_type != VAR_CHANNEL) + { + EMSG2(_(e_invarg2), get_tv_string(&argvars[0])); + rettv->vval.v_string = NULL; + } + else + rettv->vval.v_string = vim_strsave( + (char_u *)channel_status(argvars[0].vval.v_channel)); + } #endif /* *************** *** 14535,14541 **** #else garray_T ga; #endif ! jobopt_T options; rettv->v_type = VAR_JOB; job = job_alloc(); --- 14585,14591 ---- #else garray_T ga; #endif ! jobopt_T opt; rettv->v_type = VAR_JOB; job = job_alloc(); *************** *** 14546,14563 **** rettv->vval.v_job->jv_status = JOB_FAILED; /* Default mode is NL. */ ! options.jo_mode = MODE_NL; ! options.jo_callback = NULL; ! if (argvars[1].v_type != VAR_UNKNOWN) ! { ! if (argvars[1].v_type != VAR_DICT) ! { ! EMSG(_(e_invarg)); ! return; ! } ! if (get_job_options(argvars[1].vval.v_dict, &options) == FAIL) ! return; ! } #ifndef USE_ARGV ga_init2(&ga, (int)sizeof(char*), 20); --- 14596,14605 ---- rettv->vval.v_job->jv_status = JOB_FAILED; /* Default mode is NL. */ ! opt.jo_mode = MODE_NL; ! opt.jo_callback = NULL; ! if (get_job_options(&argvars[1], &opt, JO_MODE + JO_CALLBACK) == FAIL) ! return; #ifndef USE_ARGV ga_init2(&ga, (int)sizeof(char*), 20); *************** *** 14639,14650 **** ga_clear(&ga); } # endif ! mch_start_job(argv, job, &options); #else # ifdef FEAT_CHANNEL ch_logs(NULL, "Starting job: %s", (char *)cmd); # endif ! mch_start_job((char *)cmd, job, &options); #endif theend: --- 14681,14692 ---- ga_clear(&ga); } # endif ! mch_start_job(argv, job, &opt); #else # ifdef FEAT_CHANNEL ch_logs(NULL, "Starting job: %s", (char *)cmd); # endif ! mch_start_job((char *)cmd, job, &opt); #endif theend: *** ../vim-7.4.1355/src/structs.h 2016-02-16 21:02:17.603873545 +0100 --- src/structs.h 2016-02-19 22:03:14.867413067 +0100 *************** *** 1372,1384 **** int ch_refcount; /* reference count */ }; /* * Options for job and channel commands. */ typedef struct { ! ch_mode_T jo_mode; /* "mode" */ ! char_u *jo_callback; /* "callback", not allocated! */ } jobopt_T; --- 1372,1394 ---- int ch_refcount; /* reference count */ }; + #define JO_MODE 1 + #define JO_CALLBACK 2 + #define JO_WAITTIME 4 + #define JO_TIMEOUT 8 + #define JO_ALL 0xffffff + /* * Options for job and channel commands. */ typedef struct { ! int jo_set; /* JO_ bits for values that were set */ ! ! ch_mode_T jo_mode; ! char_u *jo_callback; /* not allocated! */ ! int jo_waittime; ! int jo_timeout; } jobopt_T; *** ../vim-7.4.1355/src/proto/channel.pro 2016-02-19 21:04:57.904318201 +0100 --- src/proto/channel.pro 2016-02-19 22:11:47.370008830 +0100 *************** *** 10,17 **** channel_T *channel_open(char *hostname, int port_in, int waittime, void (*close_cb)(void)); void channel_set_pipes(channel_T *channel, sock_T in, sock_T out, sock_T err); void channel_set_job(channel_T *channel, job_T *job); - void channel_set_mode(channel_T *channel, ch_mode_T mode); - void channel_set_timeout(channel_T *channel, int timeout); void channel_set_callback(channel_T *channel, char_u *callback); void channel_set_options(channel_T *channel, jobopt_T *options); void channel_set_req_callback(channel_T *channel, char_u *callback, int id); --- 10,15 ---- *** ../vim-7.4.1355/src/testdir/test_channel.vim 2016-02-18 22:58:22.731503159 +0100 --- src/testdir/test_channel.vim 2016-02-19 22:25:26.493372517 +0100 *************** *** 144,149 **** --- 144,155 ---- endif call assert_equal('got it', s:responseMsg) + " check setting options (without testing the effect) + call ch_setoptions(handle, {'callback': 's:NotUsed'}) + call ch_setoptions(handle, {'timeout': 111}) + call assert_fails("call ch_setoptions(handle, {'waittime': 111})", "E475") + call assert_fails("call ch_setoptions(handle, {'mode': 'json'})", "E475") + " Send an eval request that works. call assert_equal('ok', ch_sendexpr(handle, 'eval-works')) sleep 10m *** ../vim-7.4.1355/src/version.c 2016-02-19 21:04:57.904318201 +0100 --- src/version.c 2016-02-19 22:25:55.593065733 +0100 *************** *** 749,750 **** --- 749,752 ---- { /* Add new patch number below this line */ + /**/ + 1356, /**/ -- Not too long ago, unzipping in public was illegal... /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\ \\\ an exciting new programming language -- http://www.Zimbu.org /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///