comparison src/channel.c @ 17170:cee12488e4bc v8.1.1584

patch 8.1.1584: the evalfunc.c file is getting too big commit https://github.com/vim/vim/commit/0a1f56fcfe31be929e9cd8c3d81a984c960e4180 Author: Bram Moolenaar <Bram@vim.org> Date: Mon Jun 24 00:43:35 2019 +0200 patch 8.1.1584: the evalfunc.c file is getting too big Problem: The evalfunc.c file is getting too big. Solution: Move channel and job related functions to channel.c.
author Bram Moolenaar <Bram@vim.org>
date Mon, 24 Jun 2019 00:45:04 +0200
parents ebe9aab81898
children fd983b381ec0
comparison
equal deleted inserted replaced
17169:c06b3187f7dc 17170:cee12488e4bc
950 950
951 return channel; 951 return channel;
952 } 952 }
953 953
954 /* 954 /*
955 * Implements ch_open(). 955 * Copy callback from "src" to "dest", incrementing the refcounts.
956 */ 956 */
957 channel_T *
958 channel_open_func(typval_T *argvars)
959 {
960 char_u *address;
961 char_u *p;
962 char *rest;
963 int port;
964 jobopt_T opt;
965 channel_T *channel = NULL;
966
967 address = tv_get_string(&argvars[0]);
968 if (argvars[1].v_type != VAR_UNKNOWN
969 && (argvars[1].v_type != VAR_DICT || argvars[1].vval.v_dict == NULL))
970 {
971 emsg(_(e_invarg));
972 return NULL;
973 }
974
975 /* parse address */
976 p = vim_strchr(address, ':');
977 if (p == NULL)
978 {
979 semsg(_(e_invarg2), address);
980 return NULL;
981 }
982 *p++ = NUL;
983 port = strtol((char *)p, &rest, 10);
984 if (*address == NUL || port <= 0 || *rest != NUL)
985 {
986 p[-1] = ':';
987 semsg(_(e_invarg2), address);
988 return NULL;
989 }
990
991 /* parse options */
992 clear_job_options(&opt);
993 opt.jo_mode = MODE_JSON;
994 opt.jo_timeout = 2000;
995 if (get_job_options(&argvars[1], &opt,
996 JO_MODE_ALL + JO_CB_ALL + JO_WAITTIME + JO_TIMEOUT_ALL, 0) == FAIL)
997 goto theend;
998 if (opt.jo_timeout < 0)
999 {
1000 emsg(_(e_invarg));
1001 goto theend;
1002 }
1003
1004 channel = channel_open((char *)address, port, opt.jo_waittime, NULL);
1005 if (channel != NULL)
1006 {
1007 opt.jo_set = JO_ALL;
1008 channel_set_options(channel, &opt);
1009 }
1010 theend:
1011 free_job_options(&opt);
1012 return channel;
1013 }
1014
1015 static void 957 static void
1016 ch_close_part(channel_T *channel, ch_part_T part) 958 copy_callback(callback_T *dest, callback_T *src)
1017 { 959 {
1018 sock_T *fd = &channel->ch_part[part].ch_fd; 960 dest->cb_partial = src->cb_partial;
1019 961 if (dest->cb_partial != NULL)
1020 if (*fd != INVALID_FD) 962 {
1021 { 963 dest->cb_name = src->cb_name;
1022 if (part == PART_SOCK) 964 dest->cb_free_name = FALSE;
1023 sock_close(*fd); 965 ++dest->cb_partial->pt_refcount;
1024 else 966 }
1025 { 967 else
1026 /* When using a pty the same FD is set on multiple parts, only 968 {
1027 * close it when the last reference is closed. */ 969 dest->cb_name = vim_strsave(src->cb_name);
1028 if ((part == PART_IN || channel->CH_IN_FD != *fd) 970 dest->cb_free_name = TRUE;
1029 && (part == PART_OUT || channel->CH_OUT_FD != *fd) 971 func_ref(src->cb_name);
1030 && (part == PART_ERR || channel->CH_ERR_FD != *fd)) 972 }
1031 { 973 }
1032 #ifdef MSWIN 974
1033 if (channel->ch_named_pipe) 975 static void
1034 DisconnectNamedPipe((HANDLE)fd); 976 free_set_callback(callback_T *cbp, callback_T *callback)
1035 #endif 977 {
1036 fd_close(*fd); 978 free_callback(cbp);
1037 } 979
1038 } 980 if (callback->cb_name != NULL && *callback->cb_name != NUL)
1039 *fd = INVALID_FD; 981 copy_callback(cbp, callback);
1040 982 else
1041 /* channel is closed, may want to end the job if it was the last */ 983 cbp->cb_name = NULL;
1042 channel->ch_to_be_closed &= ~(1U << part);
1043 }
1044 }
1045
1046 void
1047 channel_set_pipes(channel_T *channel, sock_T in, sock_T out, sock_T err)
1048 {
1049 if (in != INVALID_FD)
1050 {
1051 ch_close_part(channel, PART_IN);
1052 channel->CH_IN_FD = in;
1053 # if defined(UNIX)
1054 /* Do not end the job when all output channels are closed, wait until
1055 * the job ended. */
1056 if (mch_isatty(in))
1057 channel->ch_to_be_closed |= (1U << PART_IN);
1058 # endif
1059 }
1060 if (out != INVALID_FD)
1061 {
1062 # if defined(FEAT_GUI)
1063 channel_gui_unregister_one(channel, PART_OUT);
1064 # endif
1065 ch_close_part(channel, PART_OUT);
1066 channel->CH_OUT_FD = out;
1067 channel->ch_to_be_closed |= (1U << PART_OUT);
1068 # if defined(FEAT_GUI)
1069 channel_gui_register_one(channel, PART_OUT);
1070 # endif
1071 }
1072 if (err != INVALID_FD)
1073 {
1074 # if defined(FEAT_GUI)
1075 channel_gui_unregister_one(channel, PART_ERR);
1076 # endif
1077 ch_close_part(channel, PART_ERR);
1078 channel->CH_ERR_FD = err;
1079 channel->ch_to_be_closed |= (1U << PART_ERR);
1080 # if defined(FEAT_GUI)
1081 channel_gui_register_one(channel, PART_ERR);
1082 # endif
1083 }
1084 }
1085
1086 /*
1087 * Sets the job the channel is associated with and associated options.
1088 * This does not keep a refcount, when the job is freed ch_job is cleared.
1089 */
1090 void
1091 channel_set_job(channel_T *channel, job_T *job, jobopt_T *options)
1092 {
1093 channel->ch_job = job;
1094
1095 channel_set_options(channel, options);
1096
1097 if (job->jv_in_buf != NULL)
1098 {
1099 chanpart_T *in_part = &channel->ch_part[PART_IN];
1100
1101 set_bufref(&in_part->ch_bufref, job->jv_in_buf);
1102 ch_log(channel, "reading from buffer '%s'",
1103 (char *)in_part->ch_bufref.br_buf->b_ffname);
1104 if (options->jo_set & JO_IN_TOP)
1105 {
1106 if (options->jo_in_top == 0 && !(options->jo_set & JO_IN_BOT))
1107 {
1108 /* Special mode: send last-but-one line when appending a line
1109 * to the buffer. */
1110 in_part->ch_bufref.br_buf->b_write_to_channel = TRUE;
1111 in_part->ch_buf_append = TRUE;
1112 in_part->ch_buf_top =
1113 in_part->ch_bufref.br_buf->b_ml.ml_line_count + 1;
1114 }
1115 else
1116 in_part->ch_buf_top = options->jo_in_top;
1117 }
1118 else
1119 in_part->ch_buf_top = 1;
1120 if (options->jo_set & JO_IN_BOT)
1121 in_part->ch_buf_bot = options->jo_in_bot;
1122 else
1123 in_part->ch_buf_bot = in_part->ch_bufref.br_buf->b_ml.ml_line_count;
1124 }
1125 } 984 }
1126 985
1127 /* 986 /*
1128 * Prepare buffer "buf" for writing channel output to. 987 * Prepare buffer "buf" for writing channel output to.
1129 */ 988 */
1177 1036
1178 return buf; 1037 return buf;
1179 } 1038 }
1180 1039
1181 /* 1040 /*
1182 * Copy callback from "src" to "dest", incrementing the refcounts. 1041 * Set various properties from an "opt" argument.
1183 */ 1042 */
1184 static void 1043 static void
1185 copy_callback(callback_T *dest, callback_T *src)
1186 {
1187 dest->cb_partial = src->cb_partial;
1188 if (dest->cb_partial != NULL)
1189 {
1190 dest->cb_name = src->cb_name;
1191 dest->cb_free_name = FALSE;
1192 ++dest->cb_partial->pt_refcount;
1193 }
1194 else
1195 {
1196 dest->cb_name = vim_strsave(src->cb_name);
1197 dest->cb_free_name = TRUE;
1198 func_ref(src->cb_name);
1199 }
1200 }
1201
1202 static void
1203 free_set_callback(callback_T *cbp, callback_T *callback)
1204 {
1205 free_callback(cbp);
1206
1207 if (callback->cb_name != NULL && *callback->cb_name != NUL)
1208 copy_callback(cbp, callback);
1209 else
1210 cbp->cb_name = NULL;
1211 }
1212
1213 /*
1214 * Set various properties from an "opt" argument.
1215 */
1216 void
1217 channel_set_options(channel_T *channel, jobopt_T *opt) 1044 channel_set_options(channel_T *channel, jobopt_T *opt)
1218 { 1045 {
1219 ch_part_T part; 1046 ch_part_T part;
1220 1047
1221 if (opt->jo_set & JO_MODE) 1048 if (opt->jo_set & JO_MODE)
1341 } 1168 }
1342 1169
1343 channel->ch_part[PART_OUT].ch_io = opt->jo_io[PART_OUT]; 1170 channel->ch_part[PART_OUT].ch_io = opt->jo_io[PART_OUT];
1344 channel->ch_part[PART_ERR].ch_io = opt->jo_io[PART_ERR]; 1171 channel->ch_part[PART_ERR].ch_io = opt->jo_io[PART_ERR];
1345 channel->ch_part[PART_IN].ch_io = opt->jo_io[PART_IN]; 1172 channel->ch_part[PART_IN].ch_io = opt->jo_io[PART_IN];
1173 }
1174
1175 /*
1176 * Implements ch_open().
1177 */
1178 channel_T *
1179 channel_open_func(typval_T *argvars)
1180 {
1181 char_u *address;
1182 char_u *p;
1183 char *rest;
1184 int port;
1185 jobopt_T opt;
1186 channel_T *channel = NULL;
1187
1188 address = tv_get_string(&argvars[0]);
1189 if (argvars[1].v_type != VAR_UNKNOWN
1190 && (argvars[1].v_type != VAR_DICT || argvars[1].vval.v_dict == NULL))
1191 {
1192 emsg(_(e_invarg));
1193 return NULL;
1194 }
1195
1196 /* parse address */
1197 p = vim_strchr(address, ':');
1198 if (p == NULL)
1199 {
1200 semsg(_(e_invarg2), address);
1201 return NULL;
1202 }
1203 *p++ = NUL;
1204 port = strtol((char *)p, &rest, 10);
1205 if (*address == NUL || port <= 0 || *rest != NUL)
1206 {
1207 p[-1] = ':';
1208 semsg(_(e_invarg2), address);
1209 return NULL;
1210 }
1211
1212 /* parse options */
1213 clear_job_options(&opt);
1214 opt.jo_mode = MODE_JSON;
1215 opt.jo_timeout = 2000;
1216 if (get_job_options(&argvars[1], &opt,
1217 JO_MODE_ALL + JO_CB_ALL + JO_WAITTIME + JO_TIMEOUT_ALL, 0) == FAIL)
1218 goto theend;
1219 if (opt.jo_timeout < 0)
1220 {
1221 emsg(_(e_invarg));
1222 goto theend;
1223 }
1224
1225 channel = channel_open((char *)address, port, opt.jo_waittime, NULL);
1226 if (channel != NULL)
1227 {
1228 opt.jo_set = JO_ALL;
1229 channel_set_options(channel, &opt);
1230 }
1231 theend:
1232 free_job_options(&opt);
1233 return channel;
1234 }
1235
1236 static void
1237 ch_close_part(channel_T *channel, ch_part_T part)
1238 {
1239 sock_T *fd = &channel->ch_part[part].ch_fd;
1240
1241 if (*fd != INVALID_FD)
1242 {
1243 if (part == PART_SOCK)
1244 sock_close(*fd);
1245 else
1246 {
1247 /* When using a pty the same FD is set on multiple parts, only
1248 * close it when the last reference is closed. */
1249 if ((part == PART_IN || channel->CH_IN_FD != *fd)
1250 && (part == PART_OUT || channel->CH_OUT_FD != *fd)
1251 && (part == PART_ERR || channel->CH_ERR_FD != *fd))
1252 {
1253 #ifdef MSWIN
1254 if (channel->ch_named_pipe)
1255 DisconnectNamedPipe((HANDLE)fd);
1256 #endif
1257 fd_close(*fd);
1258 }
1259 }
1260 *fd = INVALID_FD;
1261
1262 /* channel is closed, may want to end the job if it was the last */
1263 channel->ch_to_be_closed &= ~(1U << part);
1264 }
1265 }
1266
1267 void
1268 channel_set_pipes(channel_T *channel, sock_T in, sock_T out, sock_T err)
1269 {
1270 if (in != INVALID_FD)
1271 {
1272 ch_close_part(channel, PART_IN);
1273 channel->CH_IN_FD = in;
1274 # if defined(UNIX)
1275 /* Do not end the job when all output channels are closed, wait until
1276 * the job ended. */
1277 if (mch_isatty(in))
1278 channel->ch_to_be_closed |= (1U << PART_IN);
1279 # endif
1280 }
1281 if (out != INVALID_FD)
1282 {
1283 # if defined(FEAT_GUI)
1284 channel_gui_unregister_one(channel, PART_OUT);
1285 # endif
1286 ch_close_part(channel, PART_OUT);
1287 channel->CH_OUT_FD = out;
1288 channel->ch_to_be_closed |= (1U << PART_OUT);
1289 # if defined(FEAT_GUI)
1290 channel_gui_register_one(channel, PART_OUT);
1291 # endif
1292 }
1293 if (err != INVALID_FD)
1294 {
1295 # if defined(FEAT_GUI)
1296 channel_gui_unregister_one(channel, PART_ERR);
1297 # endif
1298 ch_close_part(channel, PART_ERR);
1299 channel->CH_ERR_FD = err;
1300 channel->ch_to_be_closed |= (1U << PART_ERR);
1301 # if defined(FEAT_GUI)
1302 channel_gui_register_one(channel, PART_ERR);
1303 # endif
1304 }
1305 }
1306
1307 /*
1308 * Sets the job the channel is associated with and associated options.
1309 * This does not keep a refcount, when the job is freed ch_job is cleared.
1310 */
1311 void
1312 channel_set_job(channel_T *channel, job_T *job, jobopt_T *options)
1313 {
1314 channel->ch_job = job;
1315
1316 channel_set_options(channel, options);
1317
1318 if (job->jv_in_buf != NULL)
1319 {
1320 chanpart_T *in_part = &channel->ch_part[PART_IN];
1321
1322 set_bufref(&in_part->ch_bufref, job->jv_in_buf);
1323 ch_log(channel, "reading from buffer '%s'",
1324 (char *)in_part->ch_bufref.br_buf->b_ffname);
1325 if (options->jo_set & JO_IN_TOP)
1326 {
1327 if (options->jo_in_top == 0 && !(options->jo_set & JO_IN_BOT))
1328 {
1329 /* Special mode: send last-but-one line when appending a line
1330 * to the buffer. */
1331 in_part->ch_bufref.br_buf->b_write_to_channel = TRUE;
1332 in_part->ch_buf_append = TRUE;
1333 in_part->ch_buf_top =
1334 in_part->ch_bufref.br_buf->b_ml.ml_line_count + 1;
1335 }
1336 else
1337 in_part->ch_buf_top = options->jo_in_top;
1338 }
1339 else
1340 in_part->ch_buf_top = 1;
1341 if (options->jo_set & JO_IN_BOT)
1342 in_part->ch_buf_bot = options->jo_in_bot;
1343 else
1344 in_part->ch_buf_bot = in_part->ch_bufref.br_buf->b_ml.ml_line_count;
1345 }
1346 } 1346 }
1347 1347
1348 /* 1348 /*
1349 * Set the callback for "channel"/"part" for the response with "id". 1349 * Set the callback for "channel"/"part" for the response with "id".
1350 */ 1350 */
3622 } 3622 }
3623 } 3623 }
3624 if (id >= 0) 3624 if (id >= 0)
3625 channel_remove_block_id(chanpart, id); 3625 channel_remove_block_id(chanpart, id);
3626 return FAIL; 3626 return FAIL;
3627 }
3628
3629 /*
3630 * Get the channel from the argument.
3631 * Returns NULL if the handle is invalid.
3632 * When "check_open" is TRUE check that the channel can be used.
3633 * When "reading" is TRUE "check_open" considers typeahead useful.
3634 * "part" is used to check typeahead, when PART_COUNT use the default part.
3635 */
3636 static channel_T *
3637 get_channel_arg(typval_T *tv, int check_open, int reading, ch_part_T part)
3638 {
3639 channel_T *channel = NULL;
3640 int has_readahead = FALSE;
3641
3642 if (tv->v_type == VAR_JOB)
3643 {
3644 if (tv->vval.v_job != NULL)
3645 channel = tv->vval.v_job->jv_channel;
3646 }
3647 else if (tv->v_type == VAR_CHANNEL)
3648 {
3649 channel = tv->vval.v_channel;
3650 }
3651 else
3652 {
3653 semsg(_(e_invarg2), tv_get_string(tv));
3654 return NULL;
3655 }
3656 if (channel != NULL && reading)
3657 has_readahead = channel_has_readahead(channel,
3658 part != PART_COUNT ? part : channel_part_read(channel));
3659
3660 if (check_open && (channel == NULL || (!channel_is_open(channel)
3661 && !(reading && has_readahead))))
3662 {
3663 emsg(_("E906: not an open channel"));
3664 return NULL;
3665 }
3666 return channel;
3627 } 3667 }
3628 3668
3629 /* 3669 /*
3630 * Common for ch_read() and ch_readraw(). 3670 * Common for ch_read() and ch_readraw().
3631 */ 3671 */
5191 } 5231 }
5192 5232
5193 return OK; 5233 return OK;
5194 } 5234 }
5195 5235
5196 /*
5197 * Get the channel from the argument.
5198 * Returns NULL if the handle is invalid.
5199 * When "check_open" is TRUE check that the channel can be used.
5200 * When "reading" is TRUE "check_open" considers typeahead useful.
5201 * "part" is used to check typeahead, when PART_COUNT use the default part.
5202 */
5203 channel_T *
5204 get_channel_arg(typval_T *tv, int check_open, int reading, ch_part_T part)
5205 {
5206 channel_T *channel = NULL;
5207 int has_readahead = FALSE;
5208
5209 if (tv->v_type == VAR_JOB)
5210 {
5211 if (tv->vval.v_job != NULL)
5212 channel = tv->vval.v_job->jv_channel;
5213 }
5214 else if (tv->v_type == VAR_CHANNEL)
5215 {
5216 channel = tv->vval.v_channel;
5217 }
5218 else
5219 {
5220 semsg(_(e_invarg2), tv_get_string(tv));
5221 return NULL;
5222 }
5223 if (channel != NULL && reading)
5224 has_readahead = channel_has_readahead(channel,
5225 part != PART_COUNT ? part : channel_part_read(channel));
5226
5227 if (check_open && (channel == NULL || (!channel_is_open(channel)
5228 && !(reading && has_readahead))))
5229 {
5230 emsg(_("E906: not an open channel"));
5231 return NULL;
5232 }
5233 return channel;
5234 }
5235
5236 static job_T *first_job = NULL; 5236 static job_T *first_job = NULL;
5237 5237
5238 static void 5238 static void
5239 job_free_contents(job_T *job) 5239 job_free_contents(job_T *job)
5240 { 5240 {
5974 } 5974 }
5975 return result; 5975 return result;
5976 } 5976 }
5977 5977
5978 /* 5978 /*
5979 * Implementation of job_info().
5980 */
5981 void
5982 job_info(job_T *job, dict_T *dict)
5983 {
5984 dictitem_T *item;
5985 varnumber_T nr;
5986 list_T *l;
5987 int i;
5988
5989 dict_add_string(dict, "status", (char_u *)job_status(job));
5990
5991 item = dictitem_alloc((char_u *)"channel");
5992 if (item == NULL)
5993 return;
5994 item->di_tv.v_type = VAR_CHANNEL;
5995 item->di_tv.vval.v_channel = job->jv_channel;
5996 if (job->jv_channel != NULL)
5997 ++job->jv_channel->ch_refcount;
5998 if (dict_add(dict, item) == FAIL)
5999 dictitem_free(item);
6000
6001 #ifdef UNIX
6002 nr = job->jv_pid;
6003 #else
6004 nr = job->jv_proc_info.dwProcessId;
6005 #endif
6006 dict_add_number(dict, "process", nr);
6007 dict_add_string(dict, "tty_in", job->jv_tty_in);
6008 dict_add_string(dict, "tty_out", job->jv_tty_out);
6009
6010 dict_add_number(dict, "exitval", job->jv_exitval);
6011 dict_add_string(dict, "exit_cb", job->jv_exit_cb.cb_name);
6012 dict_add_string(dict, "stoponexit", job->jv_stoponexit);
6013 #ifdef UNIX
6014 dict_add_string(dict, "termsig", job->jv_termsig);
6015 #endif
6016 #ifdef MSWIN
6017 dict_add_string(dict, "tty_type", job->jv_tty_type);
6018 #endif
6019
6020 l = list_alloc();
6021 if (l != NULL)
6022 {
6023 dict_add_list(dict, "cmd", l);
6024 if (job->jv_argv != NULL)
6025 for (i = 0; job->jv_argv[i] != NULL; i++)
6026 list_append_string(l, (char_u *)job->jv_argv[i], -1);
6027 }
6028 }
6029
6030 /*
6031 * Implementation of job_info() to return info for all jobs.
6032 */
6033 void
6034 job_info_all(list_T *l)
6035 {
6036 job_T *job;
6037 typval_T tv;
6038
6039 for (job = first_job; job != NULL; job = job->jv_next)
6040 {
6041 tv.v_type = VAR_JOB;
6042 tv.vval.v_job = job;
6043
6044 if (list_append_tv(l, &tv) != OK)
6045 return;
6046 }
6047 }
6048
6049 /*
6050 * Send a signal to "job". Implements job_stop(). 5979 * Send a signal to "job". Implements job_stop().
6051 * When "type" is not NULL use this for the type. 5980 * When "type" is not NULL use this for the type.
6052 * Otherwise use argvars[1] for the type. 5981 * Otherwise use argvars[1] for the type.
6053 */ 5982 */
6054 int 5983 int
6145 &rettv, 0, argv, NULL, 0L, 0L, &dummy, TRUE, NULL); 6074 &rettv, 0, argv, NULL, 0L, 0L, &dummy, TRUE, NULL);
6146 clear_tv(&rettv); 6075 clear_tv(&rettv);
6147 return TRUE; 6076 return TRUE;
6148 } 6077 }
6149 6078
6079 /*
6080 * "prompt_setcallback({buffer}, {callback})" function
6081 */
6082 void
6083 f_prompt_setcallback(typval_T *argvars, typval_T *rettv UNUSED)
6084 {
6085 buf_T *buf;
6086 callback_T callback;
6087
6088 if (check_secure())
6089 return;
6090 buf = tv_get_buf(&argvars[0], FALSE);
6091 if (buf == NULL)
6092 return;
6093
6094 callback = get_callback(&argvars[1]);
6095 if (callback.cb_name == NULL)
6096 return;
6097
6098 free_callback(&buf->b_prompt_callback);
6099 set_callback(&buf->b_prompt_callback, &callback);
6100 }
6101
6102 /*
6103 * "prompt_setinterrupt({buffer}, {callback})" function
6104 */
6105 void
6106 f_prompt_setinterrupt(typval_T *argvars, typval_T *rettv UNUSED)
6107 {
6108 buf_T *buf;
6109 callback_T callback;
6110
6111 if (check_secure())
6112 return;
6113 buf = tv_get_buf(&argvars[0], FALSE);
6114 if (buf == NULL)
6115 return;
6116
6117 callback = get_callback(&argvars[1]);
6118 if (callback.cb_name == NULL)
6119 return;
6120
6121 free_callback(&buf->b_prompt_interrupt);
6122 set_callback(&buf->b_prompt_interrupt, &callback);
6123 }
6124
6125 /*
6126 * "prompt_setprompt({buffer}, {text})" function
6127 */
6128 void
6129 f_prompt_setprompt(typval_T *argvars, typval_T *rettv UNUSED)
6130 {
6131 buf_T *buf;
6132 char_u *text;
6133
6134 if (check_secure())
6135 return;
6136 buf = tv_get_buf(&argvars[0], FALSE);
6137 if (buf == NULL)
6138 return;
6139
6140 text = tv_get_string(&argvars[1]);
6141 vim_free(buf->b_prompt_text);
6142 buf->b_prompt_text = vim_strsave(text);
6143 }
6144
6145 /*
6146 * "ch_canread()" function
6147 */
6148 void
6149 f_ch_canread(typval_T *argvars, typval_T *rettv)
6150 {
6151 channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
6152
6153 rettv->vval.v_number = 0;
6154 if (channel != NULL)
6155 rettv->vval.v_number = channel_has_readahead(channel, PART_SOCK)
6156 || channel_has_readahead(channel, PART_OUT)
6157 || channel_has_readahead(channel, PART_ERR);
6158 }
6159
6160 /*
6161 * "ch_close()" function
6162 */
6163 void
6164 f_ch_close(typval_T *argvars, typval_T *rettv UNUSED)
6165 {
6166 channel_T *channel = get_channel_arg(&argvars[0], TRUE, FALSE, 0);
6167
6168 if (channel != NULL)
6169 {
6170 channel_close(channel, FALSE);
6171 channel_clear(channel);
6172 }
6173 }
6174
6175 /*
6176 * "ch_close()" function
6177 */
6178 void
6179 f_ch_close_in(typval_T *argvars, typval_T *rettv UNUSED)
6180 {
6181 channel_T *channel = get_channel_arg(&argvars[0], TRUE, FALSE, 0);
6182
6183 if (channel != NULL)
6184 channel_close_in(channel);
6185 }
6186
6187 /*
6188 * "ch_getbufnr()" function
6189 */
6190 void
6191 f_ch_getbufnr(typval_T *argvars, typval_T *rettv)
6192 {
6193 channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
6194
6195 rettv->vval.v_number = -1;
6196 if (channel != NULL)
6197 {
6198 char_u *what = tv_get_string(&argvars[1]);
6199 int part;
6200
6201 if (STRCMP(what, "err") == 0)
6202 part = PART_ERR;
6203 else if (STRCMP(what, "out") == 0)
6204 part = PART_OUT;
6205 else if (STRCMP(what, "in") == 0)
6206 part = PART_IN;
6207 else
6208 part = PART_SOCK;
6209 if (channel->ch_part[part].ch_bufref.br_buf != NULL)
6210 rettv->vval.v_number =
6211 channel->ch_part[part].ch_bufref.br_buf->b_fnum;
6212 }
6213 }
6214
6215 /*
6216 * "ch_getjob()" function
6217 */
6218 void
6219 f_ch_getjob(typval_T *argvars, typval_T *rettv)
6220 {
6221 channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
6222
6223 if (channel != NULL)
6224 {
6225 rettv->v_type = VAR_JOB;
6226 rettv->vval.v_job = channel->ch_job;
6227 if (channel->ch_job != NULL)
6228 ++channel->ch_job->jv_refcount;
6229 }
6230 }
6231
6232 /*
6233 * "ch_info()" function
6234 */
6235 void
6236 f_ch_info(typval_T *argvars, typval_T *rettv UNUSED)
6237 {
6238 channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
6239
6240 if (channel != NULL && rettv_dict_alloc(rettv) != FAIL)
6241 channel_info(channel, rettv->vval.v_dict);
6242 }
6243
6244 /*
6245 * "ch_log()" function
6246 */
6247 void
6248 f_ch_log(typval_T *argvars, typval_T *rettv UNUSED)
6249 {
6250 char_u *msg = tv_get_string(&argvars[0]);
6251 channel_T *channel = NULL;
6252
6253 if (argvars[1].v_type != VAR_UNKNOWN)
6254 channel = get_channel_arg(&argvars[1], FALSE, FALSE, 0);
6255
6256 ch_log(channel, "%s", msg);
6257 }
6258
6259 /*
6260 * "ch_logfile()" function
6261 */
6262 void
6263 f_ch_logfile(typval_T *argvars, typval_T *rettv UNUSED)
6264 {
6265 char_u *fname;
6266 char_u *opt = (char_u *)"";
6267 char_u buf[NUMBUFLEN];
6268
6269 /* Don't open a file in restricted mode. */
6270 if (check_restricted() || check_secure())
6271 return;
6272 fname = tv_get_string(&argvars[0]);
6273 if (argvars[1].v_type == VAR_STRING)
6274 opt = tv_get_string_buf(&argvars[1], buf);
6275 ch_logfile(fname, opt);
6276 }
6277
6278 /*
6279 * "ch_open()" function
6280 */
6281 void
6282 f_ch_open(typval_T *argvars, typval_T *rettv)
6283 {
6284 rettv->v_type = VAR_CHANNEL;
6285 if (check_restricted() || check_secure())
6286 return;
6287 rettv->vval.v_channel = channel_open_func(argvars);
6288 }
6289
6290 /*
6291 * "ch_read()" function
6292 */
6293 void
6294 f_ch_read(typval_T *argvars, typval_T *rettv)
6295 {
6296 common_channel_read(argvars, rettv, FALSE, FALSE);
6297 }
6298
6299 /*
6300 * "ch_readblob()" function
6301 */
6302 void
6303 f_ch_readblob(typval_T *argvars, typval_T *rettv)
6304 {
6305 common_channel_read(argvars, rettv, TRUE, TRUE);
6306 }
6307
6308 /*
6309 * "ch_readraw()" function
6310 */
6311 void
6312 f_ch_readraw(typval_T *argvars, typval_T *rettv)
6313 {
6314 common_channel_read(argvars, rettv, TRUE, FALSE);
6315 }
6316
6317 /*
6318 * "ch_evalexpr()" function
6319 */
6320 void
6321 f_ch_evalexpr(typval_T *argvars, typval_T *rettv)
6322 {
6323 ch_expr_common(argvars, rettv, TRUE);
6324 }
6325
6326 /*
6327 * "ch_sendexpr()" function
6328 */
6329 void
6330 f_ch_sendexpr(typval_T *argvars, typval_T *rettv)
6331 {
6332 ch_expr_common(argvars, rettv, FALSE);
6333 }
6334
6335 /*
6336 * "ch_evalraw()" function
6337 */
6338 void
6339 f_ch_evalraw(typval_T *argvars, typval_T *rettv)
6340 {
6341 ch_raw_common(argvars, rettv, TRUE);
6342 }
6343
6344 /*
6345 * "ch_sendraw()" function
6346 */
6347 void
6348 f_ch_sendraw(typval_T *argvars, typval_T *rettv)
6349 {
6350 ch_raw_common(argvars, rettv, FALSE);
6351 }
6352
6353 /*
6354 * "ch_setoptions()" function
6355 */
6356 void
6357 f_ch_setoptions(typval_T *argvars, typval_T *rettv UNUSED)
6358 {
6359 channel_T *channel;
6360 jobopt_T opt;
6361
6362 channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
6363 if (channel == NULL)
6364 return;
6365 clear_job_options(&opt);
6366 if (get_job_options(&argvars[1], &opt,
6367 JO_CB_ALL + JO_TIMEOUT_ALL + JO_MODE_ALL, 0) == OK)
6368 channel_set_options(channel, &opt);
6369 free_job_options(&opt);
6370 }
6371
6372 /*
6373 * "ch_status()" function
6374 */
6375 void
6376 f_ch_status(typval_T *argvars, typval_T *rettv)
6377 {
6378 channel_T *channel;
6379 jobopt_T opt;
6380 int part = -1;
6381
6382 /* return an empty string by default */
6383 rettv->v_type = VAR_STRING;
6384 rettv->vval.v_string = NULL;
6385
6386 channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
6387
6388 if (argvars[1].v_type != VAR_UNKNOWN)
6389 {
6390 clear_job_options(&opt);
6391 if (get_job_options(&argvars[1], &opt, JO_PART, 0) == OK
6392 && (opt.jo_set & JO_PART))
6393 part = opt.jo_part;
6394 }
6395
6396 rettv->vval.v_string = vim_strsave((char_u *)channel_status(channel, part));
6397 }
6398
6399 /*
6400 * Get the job from the argument.
6401 * Returns NULL if the job is invalid.
6402 */
6403 static job_T *
6404 get_job_arg(typval_T *tv)
6405 {
6406 job_T *job;
6407
6408 if (tv->v_type != VAR_JOB)
6409 {
6410 semsg(_(e_invarg2), tv_get_string(tv));
6411 return NULL;
6412 }
6413 job = tv->vval.v_job;
6414
6415 if (job == NULL)
6416 emsg(_("E916: not a valid job"));
6417 return job;
6418 }
6419
6420 /*
6421 * "job_getchannel()" function
6422 */
6423 void
6424 f_job_getchannel(typval_T *argvars, typval_T *rettv)
6425 {
6426 job_T *job = get_job_arg(&argvars[0]);
6427
6428 if (job != NULL)
6429 {
6430 rettv->v_type = VAR_CHANNEL;
6431 rettv->vval.v_channel = job->jv_channel;
6432 if (job->jv_channel != NULL)
6433 ++job->jv_channel->ch_refcount;
6434 }
6435 }
6436
6437 /*
6438 * Implementation of job_info().
6439 */
6440 static void
6441 job_info(job_T *job, dict_T *dict)
6442 {
6443 dictitem_T *item;
6444 varnumber_T nr;
6445 list_T *l;
6446 int i;
6447
6448 dict_add_string(dict, "status", (char_u *)job_status(job));
6449
6450 item = dictitem_alloc((char_u *)"channel");
6451 if (item == NULL)
6452 return;
6453 item->di_tv.v_type = VAR_CHANNEL;
6454 item->di_tv.vval.v_channel = job->jv_channel;
6455 if (job->jv_channel != NULL)
6456 ++job->jv_channel->ch_refcount;
6457 if (dict_add(dict, item) == FAIL)
6458 dictitem_free(item);
6459
6460 #ifdef UNIX
6461 nr = job->jv_pid;
6462 #else
6463 nr = job->jv_proc_info.dwProcessId;
6464 #endif
6465 dict_add_number(dict, "process", nr);
6466 dict_add_string(dict, "tty_in", job->jv_tty_in);
6467 dict_add_string(dict, "tty_out", job->jv_tty_out);
6468
6469 dict_add_number(dict, "exitval", job->jv_exitval);
6470 dict_add_string(dict, "exit_cb", job->jv_exit_cb.cb_name);
6471 dict_add_string(dict, "stoponexit", job->jv_stoponexit);
6472 #ifdef UNIX
6473 dict_add_string(dict, "termsig", job->jv_termsig);
6474 #endif
6475 #ifdef MSWIN
6476 dict_add_string(dict, "tty_type", job->jv_tty_type);
6477 #endif
6478
6479 l = list_alloc();
6480 if (l != NULL)
6481 {
6482 dict_add_list(dict, "cmd", l);
6483 if (job->jv_argv != NULL)
6484 for (i = 0; job->jv_argv[i] != NULL; i++)
6485 list_append_string(l, (char_u *)job->jv_argv[i], -1);
6486 }
6487 }
6488
6489 /*
6490 * Implementation of job_info() to return info for all jobs.
6491 */
6492 static void
6493 job_info_all(list_T *l)
6494 {
6495 job_T *job;
6496 typval_T tv;
6497
6498 for (job = first_job; job != NULL; job = job->jv_next)
6499 {
6500 tv.v_type = VAR_JOB;
6501 tv.vval.v_job = job;
6502
6503 if (list_append_tv(l, &tv) != OK)
6504 return;
6505 }
6506 }
6507
6508 /*
6509 * "job_info()" function
6510 */
6511 void
6512 f_job_info(typval_T *argvars, typval_T *rettv)
6513 {
6514 if (argvars[0].v_type != VAR_UNKNOWN)
6515 {
6516 job_T *job = get_job_arg(&argvars[0]);
6517
6518 if (job != NULL && rettv_dict_alloc(rettv) != FAIL)
6519 job_info(job, rettv->vval.v_dict);
6520 }
6521 else if (rettv_list_alloc(rettv) == OK)
6522 job_info_all(rettv->vval.v_list);
6523 }
6524
6525 /*
6526 * "job_setoptions()" function
6527 */
6528 void
6529 f_job_setoptions(typval_T *argvars, typval_T *rettv UNUSED)
6530 {
6531 job_T *job = get_job_arg(&argvars[0]);
6532 jobopt_T opt;
6533
6534 if (job == NULL)
6535 return;
6536 clear_job_options(&opt);
6537 if (get_job_options(&argvars[1], &opt, JO_STOPONEXIT + JO_EXIT_CB, 0) == OK)
6538 job_set_options(job, &opt);
6539 free_job_options(&opt);
6540 }
6541
6542 /*
6543 * "job_start()" function
6544 */
6545 void
6546 f_job_start(typval_T *argvars, typval_T *rettv)
6547 {
6548 rettv->v_type = VAR_JOB;
6549 if (check_restricted() || check_secure())
6550 return;
6551 rettv->vval.v_job = job_start(argvars, NULL, NULL, FALSE);
6552 }
6553
6554 /*
6555 * "job_status()" function
6556 */
6557 void
6558 f_job_status(typval_T *argvars, typval_T *rettv)
6559 {
6560 job_T *job = get_job_arg(&argvars[0]);
6561
6562 if (job != NULL)
6563 {
6564 rettv->v_type = VAR_STRING;
6565 rettv->vval.v_string = vim_strsave((char_u *)job_status(job));
6566 }
6567 }
6568
6569 /*
6570 * "job_stop()" function
6571 */
6572 void
6573 f_job_stop(typval_T *argvars, typval_T *rettv)
6574 {
6575 job_T *job = get_job_arg(&argvars[0]);
6576
6577 if (job != NULL)
6578 rettv->vval.v_number = job_stop(job, argvars, NULL);
6579 }
6580
6150 #endif /* FEAT_JOB_CHANNEL */ 6581 #endif /* FEAT_JOB_CHANNEL */