summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2020-04-05 20:21:03 +0200
committerBram Moolenaar <Bram@vim.org>2020-04-05 20:21:03 +0200
commitf87a0400fd81862c33d6ad2291a56e178db7dddd (patch)
tree2a1ef72193db1883d8aa81c158d99148b5412fb6
parentb8ed3aa9e708ec0af4e9ee8921ad198f0e949c0d (diff)
downloadvim-git-f87a0400fd81862c33d6ad2291a56e178db7dddd.tar.gz
patch 8.2.0516: client-server code is spread outv8.2.0516
Problem: Client-server code is spread out. Solution: Move client-server code to a new file. (Yegappan Lakshmanan, closes #5885)
-rw-r--r--Filelist2
-rw-r--r--src/Make_cyg_ming.mak1
-rw-r--r--src/Make_morph.mak1
-rw-r--r--src/Make_mvc.mak4
-rw-r--r--src/Make_vms.mms6
-rw-r--r--src/Makefile10
-rw-r--r--src/README.md1
-rw-r--r--src/clientserver.c1003
-rw-r--r--src/evalfunc.c324
-rw-r--r--src/main.c673
-rw-r--r--src/proto.h1
-rw-r--r--src/proto/clientserver.pro16
-rw-r--r--src/proto/main.pro4
-rw-r--r--src/version.c2
14 files changed, 1047 insertions, 1001 deletions
diff --git a/Filelist b/Filelist
index 25bfb4c01..422a0d0ba 100644
--- a/Filelist
+++ b/Filelist
@@ -30,6 +30,7 @@ SRC_ALL = \
src/channel.c \
src/charset.c \
src/cindent.c \
+ src/clientserver.c \
src/clipboard.c \
src/cmdexpand.c \
src/cmdhist.c \
@@ -203,6 +204,7 @@ SRC_ALL = \
src/proto/channel.pro \
src/proto/charset.pro \
src/proto/cindent.pro \
+ src/proto/clientserver.pro \
src/proto/clipboard.pro \
src/proto/cmdexpand.pro \
src/proto/cmdhist.pro \
diff --git a/src/Make_cyg_ming.mak b/src/Make_cyg_ming.mak
index c51225b35..86986482a 100644
--- a/src/Make_cyg_ming.mak
+++ b/src/Make_cyg_ming.mak
@@ -710,6 +710,7 @@ OBJ = \
$(OUTDIR)/change.o \
$(OUTDIR)/charset.o \
$(OUTDIR)/cindent.o \
+ $(OUTDIR)/clientserver.o \
$(OUTDIR)/clipboard.o \
$(OUTDIR)/cmdexpand.o \
$(OUTDIR)/cmdhist.o \
diff --git a/src/Make_morph.mak b/src/Make_morph.mak
index 72731825e..1830d85b5 100644
--- a/src/Make_morph.mak
+++ b/src/Make_morph.mak
@@ -33,6 +33,7 @@ SRC = arabic.c \
change.c \
charset.c \
cindent.c \
+ clientserver.c \
clipboard.c \
cmdexpand.c \
cmdhist.c \
diff --git a/src/Make_mvc.mak b/src/Make_mvc.mak
index 86c319fd5..1d7a3ed11 100644
--- a/src/Make_mvc.mak
+++ b/src/Make_mvc.mak
@@ -730,6 +730,7 @@ OBJ = \
$(OUTDIR)\change.obj \
$(OUTDIR)\charset.obj \
$(OUTDIR)\cindent.obj \
+ $(OUTDIR)\clientserver.obj \
$(OUTDIR)\clipboard.obj \
$(OUTDIR)\cmdexpand.obj \
$(OUTDIR)\cmdhist.obj \
@@ -1516,6 +1517,8 @@ $(OUTDIR)/charset.obj: $(OUTDIR) charset.c $(INCL)
$(OUTDIR)/cindent.obj: $(OUTDIR) cindent.c $(INCL)
+$(OUTDIR)/clientserver.obj: $(OUTDIR) clientserver.c $(INCL)
+
$(OUTDIR)/clipboard.obj: $(OUTDIR) clipboard.c $(INCL)
$(OUTDIR)/cmdexpand.obj: $(OUTDIR) cmdexpand.c $(INCL)
@@ -1865,6 +1868,7 @@ proto.h: \
proto/change.pro \
proto/charset.pro \
proto/cindent.pro \
+ proto/clientserver.pro \
proto/clipboard.pro \
proto/cmdexpand.pro \
proto/cmdhist.pro \
diff --git a/src/Make_vms.mms b/src/Make_vms.mms
index ea6a8d76f..fdd7ba7c1 100644
--- a/src/Make_vms.mms
+++ b/src/Make_vms.mms
@@ -306,6 +306,7 @@ SRC = \
change.c \
charset.c \
cindent.c \
+ clientserver.c \
clipboard.c \
cmdexpand.c \
cmdhist.c \
@@ -413,6 +414,7 @@ OBJ = \
change.obj \
charset.obj \
cindent.obj \
+ clientserver.obj \
clipboard.obj \
cmdexpand.obj \
cmdhist.obj \
@@ -702,6 +704,10 @@ cindent.obj : cindent.c vim.h [.auto]config.h feature.h os_unix.h \
ascii.h keymap.h term.h macros.h structs.h regexp.h \
gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \
globals.h
+clientserver.obj : clientserver.c vim.h [.auto]config.h feature.h os_unix.h \
+ ascii.h keymap.h term.h macros.h structs.h regexp.h \
+ gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \
+ globals.h
clipboard.obj : clipboard.c vim.h [.auto]config.h feature.h os_unix.h \
ascii.h keymap.h term.h macros.h structs.h regexp.h \
gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \
diff --git a/src/Makefile b/src/Makefile
index 221b4f0de..704721b5f 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -1602,6 +1602,7 @@ BASIC_SRC = \
change.c \
charset.c \
cindent.c \
+ clientserver.c \
clipboard.c \
cmdexpand.c \
cmdhist.c \
@@ -1747,6 +1748,7 @@ OBJ_COMMON = \
objects/blob.o \
objects/blowfish.o \
objects/cindent.o \
+ objects/clientserver.o \
objects/clipboard.o \
objects/cmdexpand.o \
objects/cmdhist.o \
@@ -1908,6 +1910,7 @@ PRO_AUTO = \
channel.pro \
charset.pro \
cindent.pro \
+ clientserver.pro \
clipboard.pro \
cmdexpand.pro \
cmdhist.pro \
@@ -3123,6 +3126,9 @@ objects/charset.o: charset.c
objects/cindent.o: cindent.c
$(CCC) -o $@ cindent.c
+objects/clientserver.o: clientserver.c
+ $(CCC) -o $@ clientserver.c
+
objects/clipboard.o: clipboard.c
$(CCC) -o $@ clipboard.c
@@ -3743,6 +3749,10 @@ objects/cindent.o: cindent.c vim.h protodef.h auto/config.h feature.h os_unix.h
auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
proto.h globals.h
+objects/clientserver.o: clientserver.c vim.h protodef.h auto/config.h feature.h os_unix.h \
+ auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
+ proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
+ proto.h globals.h
objects/clipboard.o: clipboard.c vim.h protodef.h auto/config.h feature.h os_unix.h \
auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
diff --git a/src/README.md b/src/README.md
index f28788c84..54be08284 100644
--- a/src/README.md
+++ b/src/README.md
@@ -30,6 +30,7 @@ buffer.c | manipulating buffers (loaded files)
bufwrite.c | writing a buffer to file
change.c | handling changes to text
cindent.c | C and Lisp indentation
+clientserver.c | client server functionality
clipboard.c | handling the clipboard
cmdexpand.c | command-line completion
cmdhist.c | command-line history
diff --git a/src/clientserver.c b/src/clientserver.c
new file mode 100644
index 000000000..524542580
--- /dev/null
+++ b/src/clientserver.c
@@ -0,0 +1,1003 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ *
+ * Do ":help uganda" in Vim to read copying and usage conditions.
+ * Do ":help credits" in Vim to see a list of people who contributed.
+ * See README.txt for an overview of the Vim source code.
+ */
+
+/*
+ * clientserver.c: functions for Client Server functionality
+ */
+
+#include "vim.h"
+
+#if defined(FEAT_CLIENTSERVER) || defined(PROTO)
+
+static void cmdsrv_main(int *argc, char **argv, char_u *serverName_arg, char_u **serverStr);
+static char_u *serverMakeName(char_u *arg, char *cmd);
+
+/*
+ * Replace termcodes such as <CR> and insert as key presses if there is room.
+ */
+ void
+server_to_input_buf(char_u *str)
+{
+ char_u *ptr = NULL;
+ char_u *cpo_save = p_cpo;
+
+ // Set 'cpoptions' the way we want it.
+ // B set - backslashes are *not* treated specially
+ // k set - keycodes are *not* reverse-engineered
+ // < unset - <Key> sequences *are* interpreted
+ // The last but one parameter of replace_termcodes() is TRUE so that the
+ // <lt> sequence is recognised - needed for a real backslash.
+ p_cpo = (char_u *)"Bk";
+ str = replace_termcodes((char_u *)str, &ptr, REPTERM_DO_LT, NULL);
+ p_cpo = cpo_save;
+
+ if (*ptr != NUL) // trailing CTRL-V results in nothing
+ {
+ /*
+ * Add the string to the input stream.
+ * Can't use add_to_input_buf() here, we now have K_SPECIAL bytes.
+ *
+ * First clear typed characters from the typeahead buffer, there could
+ * be half a mapping there. Then append to the existing string, so
+ * that multiple commands from a client are concatenated.
+ */
+ if (typebuf.tb_maplen < typebuf.tb_len)
+ del_typebuf(typebuf.tb_len - typebuf.tb_maplen, typebuf.tb_maplen);
+ (void)ins_typebuf(str, REMAP_NONE, typebuf.tb_len, TRUE, FALSE);
+
+ // Let input_available() know we inserted text in the typeahead
+ // buffer.
+ typebuf_was_filled = TRUE;
+ }
+ vim_free((char_u *)ptr);
+}
+
+/*
+ * Evaluate an expression that the client sent to a string.
+ */
+ char_u *
+eval_client_expr_to_string(char_u *expr)
+{
+ char_u *res;
+ int save_dbl = debug_break_level;
+ int save_ro = redir_off;
+ funccal_entry_T funccal_entry;
+ int did_save_funccal = FALSE;
+
+ // Evaluate the expression at the toplevel, don't use variables local to
+ // the calling function. Except when in debug mode.
+ if (!debug_mode)
+ {
+ save_funccal(&funccal_entry);
+ did_save_funccal = TRUE;
+ }
+
+ // Disable debugging, otherwise Vim hangs, waiting for "cont" to be
+ // typed.
+ debug_break_level = -1;
+ redir_off = 0;
+ // Do not display error message, otherwise Vim hangs, waiting for "cont"
+ // to be typed. Do generate errors so that try/catch works.
+ ++emsg_silent;
+
+ res = eval_to_string(expr, NULL, TRUE);
+
+ debug_break_level = save_dbl;
+ redir_off = save_ro;
+ --emsg_silent;
+ if (emsg_silent < 0)
+ emsg_silent = 0;
+ if (did_save_funccal)
+ restore_funccal();
+
+ // A client can tell us to redraw, but not to display the cursor, so do
+ // that here.
+ setcursor();
+ out_flush_cursor(FALSE, FALSE);
+
+ return res;
+}
+
+/*
+ * Evaluate a command or expression sent to ourselves.
+ */
+ int
+sendToLocalVim(char_u *cmd, int asExpr, char_u **result)
+{
+ if (asExpr)
+ {
+ char_u *ret;
+
+ ret = eval_client_expr_to_string(cmd);
+ if (result != NULL)
+ {
+ if (ret == NULL)
+ {
+ char *err = _(e_invexprmsg);
+ size_t len = STRLEN(cmd) + STRLEN(err) + 5;
+ char_u *msg;
+
+ msg = alloc(len);
+ if (msg != NULL)
+ vim_snprintf((char *)msg, len, "%s: \"%s\"", err, cmd);
+ *result = msg;
+ }
+ else
+ *result = ret;
+ }
+ else
+ vim_free(ret);
+ return ret == NULL ? -1 : 0;
+ }
+ server_to_input_buf(cmd);
+ return 0;
+}
+
+/*
+ * If conversion is needed, convert "data" from "client_enc" to 'encoding' and
+ * return an allocated string. Otherwise return "data".
+ * "*tofree" is set to the result when it needs to be freed later.
+ */
+ char_u *
+serverConvert(
+ char_u *client_enc UNUSED,
+ char_u *data,
+ char_u **tofree)
+{
+ char_u *res = data;
+
+ *tofree = NULL;
+ if (client_enc != NULL && p_enc != NULL)
+ {
+ vimconv_T vimconv;
+
+ vimconv.vc_type = CONV_NONE;
+ if (convert_setup(&vimconv, client_enc, p_enc) != FAIL
+ && vimconv.vc_type != CONV_NONE)
+ {
+ res = string_convert(&vimconv, data, NULL);
+ if (res == NULL)
+ res = data;
+ else
+ *tofree = res;
+ }
+ convert_setup(&vimconv, NULL, NULL);
+ }
+ return res;
+}
+#endif
+
+#if (defined(FEAT_CLIENTSERVER) && !defined(NO_VIM_MAIN)) || defined(PROTO)
+
+/*
+ * Common code for the X command server and the Win32 command server.
+ */
+
+static char_u *build_drop_cmd(int filec, char **filev, int tabs, int sendReply);
+
+/*
+ * Do the client-server stuff, unless "--servername ''" was used.
+ */
+ void
+exec_on_server(mparm_T *parmp)
+{
+ if (parmp->serverName_arg == NULL || *parmp->serverName_arg != NUL)
+ {
+# ifdef MSWIN
+ // Initialise the client/server messaging infrastructure.
+ serverInitMessaging();
+# endif
+
+ /*
+ * When a command server argument was found, execute it. This may
+ * exit Vim when it was successful. Otherwise it's executed further
+ * on. Remember the encoding used here in "serverStrEnc".
+ */
+ if (parmp->serverArg)
+ {
+ cmdsrv_main(&parmp->argc, parmp->argv,
+ parmp->serverName_arg, &parmp->serverStr);
+ parmp->serverStrEnc = vim_strsave(p_enc);
+ }
+
+ // If we're still running, get the name to register ourselves.
+ // On Win32 can register right now, for X11 need to setup the
+ // clipboard first, it's further down.
+ parmp->servername = serverMakeName(parmp->serverName_arg,
+ parmp->argv[0]);
+# ifdef MSWIN
+ if (parmp->servername != NULL)
+ {
+ serverSetName(parmp->servername);
+ vim_free(parmp->servername);
+ }
+# endif
+ }
+}
+
+/*
+ * Prepare for running as a Vim server.
+ */
+ void
+prepare_server(mparm_T *parmp)
+{
+# if defined(FEAT_X11)
+ /*
+ * Register for remote command execution with :serversend and --remote
+ * unless there was a -X or a --servername '' on the command line.
+ * Only register nongui-vim's with an explicit --servername argument,
+ * or when compiling with autoservername.
+ * When running as root --servername is also required.
+ */
+ if (X_DISPLAY != NULL && parmp->servername != NULL && (
+# if defined(FEAT_AUTOSERVERNAME) || defined(FEAT_GUI)
+ (
+# if defined(FEAT_AUTOSERVERNAME)
+ 1
+# else
+ gui.in_use
+# endif
+# ifdef UNIX
+ && getuid() != ROOT_UID
+# endif
+ ) ||
+# endif
+ parmp->serverName_arg != NULL))
+ {
+ (void)serverRegisterName(X_DISPLAY, parmp->servername);
+ vim_free(parmp->servername);
+ TIME_MSG("register server name");
+ }
+ else
+ serverDelayedStartName = parmp->servername;
+# endif
+
+ /*
+ * Execute command ourselves if we're here because the send failed (or
+ * else we would have exited above).
+ */
+ if (parmp->serverStr != NULL)
+ {
+ char_u *p;
+
+ server_to_input_buf(serverConvert(parmp->serverStrEnc,
+ parmp->serverStr, &p));
+ vim_free(p);
+ }
+}
+
+ static void
+cmdsrv_main(
+ int *argc,
+ char **argv,
+ char_u *serverName_arg,
+ char_u **serverStr)
+{
+ char_u *res;
+ int i;
+ char_u *sname;
+ int ret;
+ int didone = FALSE;
+ int exiterr = 0;
+ char **newArgV = argv + 1;
+ int newArgC = 1,
+ Argc = *argc;
+ int argtype;
+#define ARGTYPE_OTHER 0
+#define ARGTYPE_EDIT 1
+#define ARGTYPE_EDIT_WAIT 2
+#define ARGTYPE_SEND 3
+ int silent = FALSE;
+ int tabs = FALSE;
+# ifndef FEAT_X11
+ HWND srv;
+# else
+ Window srv;
+
+ setup_term_clip();
+# endif
+
+ sname = serverMakeName(serverName_arg, argv[0]);
+ if (sname == NULL)
+ return;
+
+ /*
+ * Execute the command server related arguments and remove them
+ * from the argc/argv array; We may have to return into main()
+ */
+ for (i = 1; i < Argc; i++)
+ {
+ res = NULL;
+ if (STRCMP(argv[i], "--") == 0) // end of option arguments
+ {
+ for (; i < *argc; i++)
+ {
+ *newArgV++ = argv[i];
+ newArgC++;
+ }
+ break;
+ }
+
+ if (STRICMP(argv[i], "--remote-send") == 0)
+ argtype = ARGTYPE_SEND;
+ else if (STRNICMP(argv[i], "--remote", 8) == 0)
+ {
+ char *p = argv[i] + 8;
+
+ argtype = ARGTYPE_EDIT;
+ while (*p != NUL)
+ {
+ if (STRNICMP(p, "-wait", 5) == 0)
+ {
+ argtype = ARGTYPE_EDIT_WAIT;
+ p += 5;
+ }
+ else if (STRNICMP(p, "-silent", 7) == 0)
+ {
+ silent = TRUE;
+ p += 7;
+ }
+ else if (STRNICMP(p, "-tab", 4) == 0)
+ {
+ tabs = TRUE;
+ p += 4;
+ }
+ else
+ {
+ argtype = ARGTYPE_OTHER;
+ break;
+ }
+ }
+ }
+ else
+ argtype = ARGTYPE_OTHER;
+
+ if (argtype != ARGTYPE_OTHER)
+ {
+ if (i == *argc - 1)
+ mainerr_arg_missing((char_u *)argv[i]);
+ if (argtype == ARGTYPE_SEND)
+ {
+ *serverStr = (char_u *)argv[i + 1];
+ i++;
+ }
+ else
+ {
+ *serverStr = build_drop_cmd(*argc - i - 1, argv + i + 1,
+ tabs, argtype == ARGTYPE_EDIT_WAIT);
+ if (*serverStr == NULL)
+ {
+ // Probably out of memory, exit.
+ didone = TRUE;
+ exiterr = 1;
+ break;
+ }
+ Argc = i;
+ }
+# ifdef FEAT_X11
+ if (xterm_dpy == NULL)
+ {
+ mch_errmsg(_("No display"));
+ ret = -1;
+ }
+ else
+ ret = serverSendToVim(xterm_dpy, sname, *serverStr,
+ NULL, &srv, 0, 0, 0, silent);
+# else
+ // Win32 always works?
+ ret = serverSendToVim(sname, *serverStr, NULL, &srv, 0, 0, silent);
+# endif
+ if (ret < 0)
+ {
+ if (argtype == ARGTYPE_SEND)
+ {
+ // Failed to send, abort.
+ mch_errmsg(_(": Send failed.\n"));
+ didone = TRUE;
+ exiterr = 1;
+ }
+ else if (!silent)
+ // Let vim start normally.
+ mch_errmsg(_(": Send failed. Trying to execute locally\n"));
+ break;
+ }
+
+# ifdef FEAT_GUI_MSWIN
+ // Guess that when the server name starts with "g" it's a GUI
+ // server, which we can bring to the foreground here.
+ // Foreground() in the server doesn't work very well.
+ if (argtype != ARGTYPE_SEND && TOUPPER_ASC(*sname) == 'G')
+ SetForegroundWindow(srv);
+# endif
+
+ /*
+ * For --remote-wait: Wait until the server did edit each
+ * file. Also detect that the server no longer runs.
+ */
+ if (ret >= 0 && argtype == ARGTYPE_EDIT_WAIT)
+ {
+ int numFiles = *argc - i - 1;
+ int j;
+ char_u *done = alloc(numFiles);
+ char_u *p;
+# ifdef FEAT_GUI_MSWIN
+ NOTIFYICONDATA ni;
+ int count = 0;
+ extern HWND message_window;
+# endif
+
+ if (numFiles > 0 && argv[i + 1][0] == '+')
+ // Skip "+cmd" argument, don't wait for it to be edited.
+ --numFiles;
+
+# ifdef FEAT_GUI_MSWIN
+ ni.cbSize = sizeof(ni);
+ ni.hWnd = message_window;
+ ni.uID = 0;
+ ni.uFlags = NIF_ICON|NIF_TIP;
+ ni.hIcon = LoadIcon((HINSTANCE)GetModuleHandle(0), "IDR_VIM");
+ sprintf(ni.szTip, _("%d of %d edited"), count, numFiles);
+ Shell_NotifyIcon(NIM_ADD, &ni);
+# endif
+
+ // Wait for all files to unload in remote
+ vim_memset(done, 0, numFiles);
+ while (memchr(done, 0, numFiles) != NULL)
+ {
+# ifdef MSWIN
+ p = serverGetReply(srv, NULL, TRUE, TRUE, 0);
+ if (p == NULL)
+ break;
+# else
+ if (serverReadReply(xterm_dpy, srv, &p, TRUE, -1) < 0)
+ break;
+# endif
+ j = atoi((char *)p);
+ if (j >= 0 && j < numFiles)
+ {
+# ifdef FEAT_GUI_MSWIN
+ ++count;
+ sprintf(ni.szTip, _("%d of %d edited"),
+ count, numFiles);
+ Shell_NotifyIcon(NIM_MODIFY, &ni);
+# endif
+ done[j] = 1;
+ }
+ }
+# ifdef FEAT_GUI_MSWIN
+ Shell_NotifyIcon(NIM_DELETE, &ni);
+# endif
+ }
+ }
+ else if (STRICMP(argv[i], "--remote-expr") == 0)
+ {
+ if (i == *argc - 1)
+ mainerr_arg_missing((char_u *)argv[i]);
+# ifdef MSWIN
+ // Win32 always works?
+ if (serverSendToVim(sname, (char_u *)argv[i + 1],
+ &res, NULL, 1, 0, FALSE) < 0)
+# else
+ if (xterm_dpy == NULL)
+ mch_errmsg(_("No display: Send expression failed.\n"));
+ else if (serverSendToVim(xterm_dpy, sname, (char_u *)argv[i + 1],
+ &res, NULL, 1, 0, 1, FALSE) < 0)
+# endif
+ {
+ if (res != NULL && *res != NUL)
+ {
+ // Output error from remote
+ mch_errmsg((char *)res);
+ VIM_CLEAR(res);
+ }
+ mch_errmsg(_(": Send expression failed.\n"));
+ }
+ }
+ else if (STRICMP(argv[i], "--serverlist") == 0)
+ {
+# ifdef MSWIN
+ // Win32 always works?
+ res = serverGetVimNames();
+# else
+ if (xterm_dpy != NULL)
+ res = serverGetVimNames(xterm_dpy);
+# endif
+ if (did_emsg)
+ mch_errmsg("\n");
+ }
+ else if (STRICMP(argv[i], "--servername") == 0)
+ {
+ // Already processed. Take it out of the command line
+ i++;
+ continue;
+ }
+ else
+ {
+ *newArgV++ = argv[i];
+ newArgC++;
+ continue;
+ }
+ didone = TRUE;
+ if (res != NULL && *res != NUL)
+ {
+ mch_msg((char *)res);
+ if (res[STRLEN(res) - 1] != '\n')
+ mch_msg("\n");
+ }
+ vim_free(res);
+ }
+
+ if (didone)
+ {
+ display_errors(); // display any collected messages
+ exit(exiterr); // Mission accomplished - get out
+ }
+
+ // Return back into main()
+ *argc = newArgC;
+ vim_free(sname);
+}
+
+/*
+ * Build a ":drop" command to send to a Vim server.
+ */
+ static char_u *
+build_drop_cmd(
+ int filec,
+ char **filev,
+ int tabs, // Use ":tab drop" instead of ":drop".
+ int sendReply)
+{
+ garray_T ga;
+ int i;
+ char_u *inicmd = NULL;
+ char_u *p;
+ char_u *cdp;
+ char_u *cwd;
+
+ if (filec > 0 && filev[0][0] == '+')
+ {
+ inicmd = (char_u *)filev[0] + 1;
+ filev++;
+ filec--;
+ }
+ // Check if we have at least one argument.
+ if (filec <= 0)
+ mainerr_arg_missing((char_u *)filev[-1]);
+
+ // Temporarily cd to the current directory to handle relative file names.
+ cwd = alloc(MAXPATHL);
+ if (cwd == NULL)
+ return NULL;
+ if (mch_dirname(cwd, MAXPATHL) != OK)
+ {
+ vim_free(cwd);
+ return NULL;
+ }
+ cdp = vim_strsave_escaped_ext(cwd,
+#ifdef BACKSLASH_IN_FILENAME
+ (char_u *)"", // rem_backslash() will tell what chars to escape
+#else
+ PATH_ESC_CHARS,
+#endif
+ '\\', TRUE);
+ vim_free(cwd);
+ if (cdp == NULL)
+ return NULL;
+ ga_init2(&ga, 1, 100);
+ ga_concat(&ga, (char_u *)"<C-\\><C-N>:cd ");
+ ga_concat(&ga, cdp);
+
+ // Call inputsave() so that a prompt for an encryption key works.
+ ga_concat(&ga, (char_u *)"<CR>:if exists('*inputsave')|call inputsave()|endif|");
+ if (tabs)
+ ga_concat(&ga, (char_u *)"tab ");
+ ga_concat(&ga, (char_u *)"drop");
+ for (i = 0; i < filec; i++)
+ {
+ // On Unix the shell has already expanded the wildcards, don't want to
+ // do it again in the Vim server. On MS-Windows only escape
+ // non-wildcard characters.
+ p = vim_strsave_escaped((char_u *)filev[i],
+#ifdef UNIX
+ PATH_ESC_CHARS
+#else
+ (char_u *)" \t%#"
+#endif
+ );
+ if (p == NULL)
+ {
+ vim_free(ga.ga_data);
+ return NULL;
+ }
+ ga_concat(&ga, (char_u *)" ");
+ ga_concat(&ga, p);
+ vim_free(p);
+ }
+ ga_concat(&ga, (char_u *)"|if exists('*inputrestore')|call inputrestore()|endif<CR>");
+
+ // The :drop commands goes to Insert mode when 'insertmode' is set, use
+ // CTRL-\ CTRL-N again.
+ ga_concat(&ga, (char_u *)"<C-\\><C-N>");
+
+ // Switch back to the correct current directory (prior to temporary path
+ // switch) unless 'autochdir' is set, in which case it will already be
+ // correct after the :drop command. With line breaks and spaces:
+ // if !exists('+acd') || !&acd
+ // if haslocaldir()
+ // cd -
+ // lcd -
+ // elseif getcwd() ==# 'current path'
+ // cd -
+ // endif
+ // endif
+ ga_concat(&ga, (char_u *)":if !exists('+acd')||!&acd|if haslocaldir()|");
+ ga_concat(&ga, (char_u *)"cd -|lcd -|elseif getcwd() ==# '");
+ ga_concat(&ga, cdp);
+ ga_concat(&ga, (char_u *)"'|cd -|endif|endif<CR>");
+ vim_free(cdp);
+
+ if (sendReply)
+ ga_concat(&ga, (char_u *)":call SetupRemoteReplies()<CR>");
+ ga_concat(&ga, (char_u *)":");
+ if (inicmd != NULL)
+ {
+ // Can't use <CR> after "inicmd", because an "startinsert" would cause
+ // the following commands to be inserted as text. Use a "|",
+ // hopefully "inicmd" does allow this...
+ ga_concat(&ga, inicmd);
+ ga_concat(&ga, (char_u *)"|");
+ }
+ // Bring the window to the foreground, goto Insert mode when 'im' set and
+ // clear command line.
+ ga_concat(&ga, (char_u *)"cal foreground()|if &im|star|en|redr|f<CR>");
+ ga_append(&ga, NUL);
+ return ga.ga_data;
+}
+
+/*
+ * Make our basic server name: use the specified "arg" if given, otherwise use
+ * the tail of the command "cmd" we were started with.
+ * Return the name in allocated memory. This doesn't include a serial number.
+ */
+ static char_u *
+serverMakeName(char_u *arg, char *cmd)
+{
+ char_u *p;
+
+ if (arg != NULL && *arg != NUL)
+ p = vim_strsave_up(arg);
+ else
+ {
+ p = vim_strsave_up(gettail((char_u *)cmd));
+ // Remove .exe or .bat from the name.
+ if (p != NULL && vim_strchr(p, '.') != NULL)
+ *vim_strchr(p, '.') = NUL;
+ }
+ return p;
+}
+#endif // FEAT_CLIENTSERVER
+
+#if defined(FEAT_CLIENTSERVER) && defined(FEAT_X11)
+ static void
+make_connection(void)
+{
+ if (X_DISPLAY == NULL
+# ifdef FEAT_GUI
+ && !gui.in_use
+# endif
+ )
+ {
+ x_force_connect = TRUE;
+ setup_term_clip();
+ x_force_connect = FALSE;
+ }
+}
+
+ static int
+check_connection(void)
+{
+ make_connection();
+ if (X_DISPLAY == NULL)
+ {
+ emsg(_("E240: No connection to the X server"));
+ return FAIL;
+ }
+ return OK;
+}
+#endif
+
+#ifdef FEAT_CLIENTSERVER
+ static void
+remote_common(typval_T *argvars, typval_T *rettv, int expr)
+{
+ char_u *server_name;
+ char_u *keys;
+ char_u *r = NULL;
+ char_u buf[NUMBUFLEN];
+ int timeout = 0;
+# ifdef MSWIN
+ HWND w;
+# else
+ Window w;
+# endif
+
+ if (check_restricted() || check_secure())
+ return;
+
+# ifdef FEAT_X11
+ if (check_connection() == FAIL)
+ return;
+# endif
+ if (argvars[2].v_type != VAR_UNKNOWN
+ && argvars[3].v_type != VAR_UNKNOWN)
+ timeout = tv_get_number(&argvars[3]);
+
+ server_name = tv_get_string_chk(&argvars[0]);
+ if (server_name == NULL)
+ return; // type error; errmsg already given
+ keys = tv_get_string_buf(&argvars[1], buf);
+# ifdef MSWIN
+ if (serverSendToVim(server_name, keys, &r, &w, expr, timeout, TRUE) < 0)
+# else
+ if (serverSendToVim(X_DISPLAY, server_name, keys, &r, &w, expr, timeout,
+ 0, TRUE) < 0)
+# endif
+ {
+ if (r != NULL)
+ {
+ emsg((char *)r); // sending worked but evaluation failed
+ vim_free(r);
+ }
+ else
+ semsg(_("E241: Unable to send to %s"), server_name);
+ return;
+ }
+
+ rettv->vval.v_string = r;
+
+ if (argvars[2].v_type != VAR_UNKNOWN)
+ {
+ dictitem_T v;
+ char_u str[30];
+ char_u *idvar;
+
+ idvar = tv_get_string_chk(&argvars[2]);
+ if (idvar != NULL && *idvar != NUL)
+ {
+ sprintf((char *)str, PRINTF_HEX_LONG_U, (long_u)w);
+ v.di_tv.v_type = VAR_STRING;
+ v.di_tv.vval.v_string = vim_strsave(str);
+ set_var(idvar, &v.di_tv, FALSE);
+ vim_free(v.di_tv.vval.v_string);
+ }
+ }
+}
+#endif
+
+#if defined(FEAT_EVAL) || defined(PROTO)
+/*
+ * "remote_expr()" function
+ */
+ void
+f_remote_expr(typval_T *argvars UNUSED, typval_T *rettv)
+{
+ rettv->v_type = VAR_STRING;
+ rettv->vval.v_string = NULL;
+#ifdef FEAT_CLIENTSERVER
+ remote_common(argvars, rettv, TRUE);
+#endif
+}
+
+/*
+ * "remote_foreground()" function
+ */
+ void
+f_remote_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
+{
+#ifdef FEAT_CLIENTSERVER
+# ifdef MSWIN
+ // On Win32 it's done in this application.
+ {
+ char_u *server_name = tv_get_string_chk(&argvars[0]);
+
+ if (server_name != NULL)
+ serverForeground(server_name);
+ }
+# else
+ // Send a foreground() expression to the server.
+ argvars[1].v_type = VAR_STRING;
+ argvars[1].vval.v_string = vim_strsave((char_u *)"foreground()");
+ argvars[2].v_type = VAR_UNKNOWN;
+ rettv->v_type = VAR_STRING;
+ rettv->vval.v_string = NULL;
+ remote_common(argvars, rettv, TRUE);
+ vim_free(argvars[1].vval.v_string);
+# endif
+#endif
+}
+
+ void
+f_remote_peek(typval_T *argvars UNUSED, typval_T *rettv)
+{
+#ifdef FEAT_CLIENTSERVER
+ dictitem_T v;
+ char_u *s = NULL;
+# ifdef MSWIN
+ long_u n = 0;
+# endif
+ char_u *serverid;
+
+ if (check_restricted() || check_secure())
+ {
+ rettv->vval.v_number = -1;
+ return;
+ }
+ serverid = tv_get_string_chk(&argvars[0]);
+ if (serverid == NULL)
+ {
+ rettv->vval.v_number = -1;
+ return; // type error; errmsg already given
+ }
+# ifdef MSWIN
+ sscanf((const char *)serverid, SCANF_HEX_LONG_U, &n);
+ if (n == 0)
+ rettv->vval.v_number = -1;
+ else
+ {
+ s = serverGetReply((HWND)n, FALSE, FALSE, FALSE, 0);
+ rettv->vval.v_number = (s != NULL);
+ }
+# else
+ if (check_connection() == FAIL)
+ return;
+
+ rettv->vval.v_number = serverPeekReply(X_DISPLAY,
+ serverStrToWin(serverid), &s);
+# endif
+
+ if (argvars[1].v_type != VAR_UNKNOWN && rettv->vval.v_number > 0)
+ {
+ char_u *retvar;
+
+ v.di_tv.v_type = VAR_STRING;
+ v.di_tv.vval.v_string = vim_strsave(s);
+ retvar = tv_get_string_chk(&argvars[1]);
+ if (retvar != NULL)
+ set_var(retvar, &v.di_tv, FALSE);
+ vim_free(v.di_tv.vval.v_string);
+ }
+#else
+ rettv->vval.v_number = -1;
+#endif
+}
+
+ void
+f_remote_read(typval_T *argvars UNUSED, typval_T *rettv)
+{
+ char_u *r = NULL;
+
+#ifdef FEAT_CLIENTSERVER
+ char_u *serverid = tv_get_string_chk(&argvars[0]);
+
+ if (serverid != NULL && !check_restricted() && !check_secure())
+ {
+ int timeout = 0;
+# ifdef MSWIN
+ // The server's HWND is encoded in the 'id' parameter
+ long_u n = 0;
+# endif
+
+ if (argvars[1].v_type != VAR_UNKNOWN)
+ timeout = tv_get_number(&argvars[1]);
+
+# ifdef MSWIN
+ sscanf((char *)serverid, SCANF_HEX_LONG_U, &n);
+ if (n != 0)
+ r = serverGetReply((HWND)n, FALSE, TRUE, TRUE, timeout);
+ if (r == NULL)
+# else
+ if (check_connection() == FAIL
+ || serverReadReply(X_DISPLAY, serverStrToWin(serverid),
+ &r, FALSE, timeout) < 0)
+# endif
+ emsg(_("E277: Unable to read a server reply"));
+ }
+#endif
+ rettv->v_type = VAR_STRING;
+ rettv->vval.v_string = r;
+}
+
+/*
+ * "remote_send()" function
+ */
+ void
+f_remote_send(typval_T *argvars UNUSED, typval_T *rettv)
+{
+ rettv->v_type = VAR_STRING;
+ rettv->vval.v_string = NULL;
+#ifdef FEAT_CLIENTSERVER
+ remote_common(argvars, rettv, FALSE);
+#endif
+}
+
+/*
+ * "remote_startserver()" function
+ */
+ void
+f_remote_startserver(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
+{
+#ifdef FEAT_CLIENTSERVER
+ char_u *server = tv_get_string_chk(&argvars[0]);
+
+ if (server == NULL)
+ return; // type error; errmsg already given
+ if (serverName != NULL)
+ emsg(_("E941: already started a server"));
+ else
+ {
+# ifdef FEAT_X11
+ if (check_connection() == OK)
+ serverRegisterName(X_DISPLAY, server);
+# else
+ serverSetName(server);
+# endif
+ }
+#else
+ emsg(_("E942: +clientserver feature not available"));
+#endif
+}
+
+ void
+f_server2client(typval_T *argvars UNUSED, typval_T *rettv)
+{
+#ifdef FEAT_CLIENTSERVER
+ char_u buf[NUMBUFLEN];
+ char_u *server = tv_get_string_chk(&argvars[0]);
+ char_u *reply = tv_get_string_buf_chk(&argvars[1], buf);
+
+ rettv->vval.v_number = -1;
+ if (server == NULL || reply == NULL)
+ return;
+ if (check_restricted() || check_secure())
+ return;
+# ifdef FEAT_X11
+ if (check_connection() == FAIL)
+ return;
+# endif
+
+ if (serverSendReply(server, reply) < 0)
+ {
+ emsg(_("E258: Unable to send to client"));
+ return;
+ }
+ rettv->vval.v_number = 0;
+#else
+ rettv->vval.v_number = -1;
+#endif
+}
+
+ void
+f_serverlist(typval_T *argvars UNUSED, typval_T *rettv)
+{
+ char_u *r = NULL;
+
+#ifdef FEAT_CLIENTSERVER
+# ifdef MSWIN
+ r = serverGetVimNames();
+# else
+ make_connection();
+ if (X_DISPLAY != NULL)
+ r = serverGetVimNames(X_DISPLAY);
+# endif
+#endif
+ rettv->v_type = VAR_STRING;
+ rettv->vval.v_string = r;
+}
+#endif
diff --git a/src/evalfunc.c b/src/evalfunc.c
index f43ac082c..5a5daaa5a 100644
--- a/src/evalfunc.c
+++ b/src/evalfunc.c
@@ -168,12 +168,6 @@ static void f_rand(typval_T *argvars, typval_T *rettv);
static void f_range(typval_T *argvars, typval_T *rettv);
static void f_reg_executing(typval_T *argvars, typval_T *rettv);
static void f_reg_recording(typval_T *argvars, typval_T *rettv);
-static void f_remote_expr(typval_T *argvars, typval_T *rettv);
-static void f_remote_foreground(typval_T *argvars, typval_T *rettv);
-static void f_remote_peek(typval_T *argvars, typval_T *rettv);
-static void f_remote_read(typval_T *argvars, typval_T *rettv);
-static void f_remote_send(typval_T *argvars, typval_T *rettv);
-static void f_remote_startserver(typval_T *argvars, typval_T *rettv);
static void f_rename(typval_T *argvars, typval_T *rettv);
static void f_repeat(typval_T *argvars, typval_T *rettv);
#ifdef FEAT_FLOAT
@@ -193,8 +187,6 @@ static void f_searchdecl(typval_T *argvars, typval_T *rettv);
static void f_searchpair(typval_T *argvars, typval_T *rettv);
static void f_searchpairpos(typval_T *argvars, typval_T *rettv);
static void f_searchpos(typval_T *argvars, typval_T *rettv);
-static void f_server2client(typval_T *argvars, typval_T *rettv);
-static void f_serverlist(typval_T *argvars, typval_T *rettv);
static void f_setcharsearch(typval_T *argvars, typval_T *rettv);
static void f_setenv(typval_T *argvars, typval_T *rettv);
static void f_setfperm(typval_T *argvars, typval_T *rettv);
@@ -6335,275 +6327,6 @@ f_reg_recording(typval_T *argvars UNUSED, typval_T *rettv)
return_register(reg_recording, rettv);
}
-#if defined(FEAT_CLIENTSERVER) && defined(FEAT_X11)
- static void
-make_connection(void)
-{
- if (X_DISPLAY == NULL
-# ifdef FEAT_GUI
- && !gui.in_use
-# endif
- )
- {
- x_force_connect = TRUE;
- setup_term_clip();
- x_force_connect = FALSE;
- }
-}
-
- static int
-check_connection(void)
-{
- make_connection();
- if (X_DISPLAY == NULL)
- {
- emsg(_("E240: No connection to the X server"));
- return FAIL;
- }
- return OK;
-}
-#endif
-
-#ifdef FEAT_CLIENTSERVER
- static void
-remote_common(typval_T *argvars, typval_T *rettv, int expr)
-{
- char_u *server_name;
- char_u *keys;
- char_u *r = NULL;
- char_u buf[NUMBUFLEN];
- int timeout = 0;
-# ifdef MSWIN
- HWND w;
-# else
- Window w;
-# endif
-
- if (check_restricted() || check_secure())
- return;
-
-# ifdef FEAT_X11
- if (check_connection() == FAIL)
- return;
-# endif
- if (argvars[2].v_type != VAR_UNKNOWN
- && argvars[3].v_type != VAR_UNKNOWN)
- timeout = tv_get_number(&argvars[3]);
-
- server_name = tv_get_string_chk(&argvars[0]);
- if (server_name == NULL)
- return; // type error; errmsg already given
- keys = tv_get_string_buf(&argvars[1], buf);
-# ifdef MSWIN
- if (serverSendToVim(server_name, keys, &r, &w, expr, timeout, TRUE) < 0)
-# else
- if (serverSendToVim(X_DISPLAY, server_name, keys, &r, &w, expr, timeout,
- 0, TRUE) < 0)
-# endif
- {
- if (r != NULL)
- {
- emsg((char *)r); // sending worked but evaluation failed
- vim_free(r);
- }
- else
- semsg(_("E241: Unable to send to %s"), server_name);
- return;
- }
-
- rettv->vval.v_string = r;
-
- if (argvars[2].v_type != VAR_UNKNOWN)
- {
- dictitem_T v;
- char_u str[30];
- char_u *idvar;
-
- idvar = tv_get_string_chk(&argvars[2]);
- if (idvar != NULL && *idvar != NUL)
- {
- sprintf((char *)str, PRINTF_HEX_LONG_U, (long_u)w);
- v.di_tv.v_type = VAR_STRING;
- v.di_tv.vval.v_string = vim_strsave(str);
- set_var(idvar, &v.di_tv, FALSE);
- vim_free(v.di_tv.vval.v_string);
- }
- }
-}
-#endif
-
-/*
- * "remote_expr()" function
- */
- static void
-f_remote_expr(typval_T *argvars UNUSED, typval_T *rettv)
-{
- rettv->v_type = VAR_STRING;
- rettv->vval.v_string = NULL;
-#ifdef FEAT_CLIENTSERVER
- remote_common(argvars, rettv, TRUE);
-#endif
-}
-
-/*
- * "remote_foreground()" function
- */
- static void
-f_remote_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
-{
-#ifdef FEAT_CLIENTSERVER
-# ifdef MSWIN
- // On Win32 it's done in this application.
- {
- char_u *server_name = tv_get_string_chk(&argvars[0]);
-
- if (server_name != NULL)
- serverForeground(server_name);
- }
-# else
- // Send a foreground() expression to the server.
- argvars[1].v_type = VAR_STRING;
- argvars[1].vval.v_string = vim_strsave((char_u *)"foreground()");
- argvars[2].v_type = VAR_UNKNOWN;
- rettv->v_type = VAR_STRING;
- rettv->vval.v_string = NULL;
- remote_common(argvars, rettv, TRUE);
- vim_free(argvars[1].vval.v_string);
-# endif
-#endif
-}
-
- static void
-f_remote_peek(typval_T *argvars UNUSED, typval_T *rettv)
-{
-#ifdef FEAT_CLIENTSERVER
- dictitem_T v;
- char_u *s = NULL;
-# ifdef MSWIN
- long_u n = 0;
-# endif
- char_u *serverid;
-
- if (check_restricted() || check_secure())
- {
- rettv->vval.v_number = -1;
- return;
- }
- serverid = tv_get_string_chk(&argvars[0]);
- if (serverid == NULL)
- {
- rettv->vval.v_number = -1;
- return; // type error; errmsg already given
- }
-# ifdef MSWIN
- sscanf((const char *)serverid, SCANF_HEX_LONG_U, &n);
- if (n == 0)
- rettv->vval.v_number = -1;
- else
- {
- s = serverGetReply((HWND)n, FALSE, FALSE, FALSE, 0);
- rettv->vval.v_number = (s != NULL);
- }
-# else
- if (check_connection() == FAIL)
- return;
-
- rettv->vval.v_number = serverPeekReply(X_DISPLAY,
- serverStrToWin(serverid), &s);
-# endif
-
- if (argvars[1].v_type != VAR_UNKNOWN && rettv->vval.v_number > 0)
- {
- char_u *retvar;
-
- v.di_tv.v_type = VAR_STRING;
- v.di_tv.vval.v_string = vim_strsave(s);
- retvar = tv_get_string_chk(&argvars[1]);
- if (retvar != NULL)
- set_var(retvar, &v.di_tv, FALSE);
- vim_free(v.di_tv.vval.v_string);
- }
-#else
- rettv->vval.v_number = -1;
-#endif
-}
-
- static void
-f_remote_read(typval_T *argvars UNUSED, typval_T *rettv)
-{
- char_u *r = NULL;
-
-#ifdef FEAT_CLIENTSERVER
- char_u *serverid = tv_get_string_chk(&argvars[0]);
-
- if (serverid != NULL && !check_restricted() && !check_secure())
- {
- int timeout = 0;
-# ifdef MSWIN
- // The server's HWND is encoded in the 'id' parameter
- long_u n = 0;
-# endif
-
- if (argvars[1].v_type != VAR_UNKNOWN)
- timeout = tv_get_number(&argvars[1]);
-
-# ifdef MSWIN
- sscanf((char *)serverid, SCANF_HEX_LONG_U, &n);
- if (n != 0)
- r = serverGetReply((HWND)n, FALSE, TRUE, TRUE, timeout);
- if (r == NULL)
-# else
- if (check_connection() == FAIL
- || serverReadReply(X_DISPLAY, serverStrToWin(serverid),
- &r, FALSE, timeout) < 0)
-# endif
- emsg(_("E277: Unable to read a server reply"));
- }
-#endif
- rettv->v_type = VAR_STRING;
- rettv->vval.v_string = r;
-}
-
-/*
- * "remote_send()" function
- */
- static void
-f_remote_send(typval_T *argvars UNUSED, typval_T *rettv)
-{
- rettv->v_type = VAR_STRING;
- rettv->vval.v_string = NULL;
-#ifdef FEAT_CLIENTSERVER
- remote_common(argvars, rettv, FALSE);
-#endif
-}
-
-/*
- * "remote_startserver()" function
- */
- static void
-f_remote_startserver(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
-{
-#ifdef FEAT_CLIENTSERVER
- char_u *server = tv_get_string_chk(&argvars[0]);
-
- if (server == NULL)
- return; // type error; errmsg already given
- if (serverName != NULL)
- emsg(_("E941: already started a server"));
- else
- {
-# ifdef FEAT_X11
- if (check_connection() == OK)
- serverRegisterName(X_DISPLAY, server);
-# else
- serverSetName(server);
-# endif
- }
-#else
- emsg(_("E942: +clientserver feature not available"));
-#endif
-}
-
/*
* "rename({from}, {to})" function
*/
@@ -7374,53 +7097,6 @@ f_searchpos(typval_T *argvars, typval_T *rettv)
}
static void
-f_server2client(typval_T *argvars UNUSED, typval_T *rettv)
-{
-#ifdef FEAT_CLIENTSERVER
- char_u buf[NUMBUFLEN];
- char_u *server = tv_get_string_chk(&argvars[0]);
- char_u *reply = tv_get_string_buf_chk(&argvars[1], buf);
-
- rettv->vval.v_number = -1;
- if (server == NULL || reply == NULL)
- return;
- if (check_restricted() || check_secure())
- return;
-# ifdef FEAT_X11
- if (check_connection() == FAIL)
- return;
-# endif
-
- if (serverSendReply(server, reply) < 0)
- {
- emsg(_("E258: Unable to send to client"));
- return;
- }
- rettv->vval.v_number = 0;
-#else
- rettv->vval.v_number = -1;
-#endif
-}
-
- static void
-f_serverlist(typval_T *argvars UNUSED, typval_T *rettv)
-{
- char_u *r = NULL;
-
-#ifdef FEAT_CLIENTSERVER
-# ifdef MSWIN
- r = serverGetVimNames();
-# else
- make_connection();
- if (X_DISPLAY != NULL)
- r = serverGetVimNames(X_DISPLAY);
-# endif
-#endif
- rettv->v_type = VAR_STRING;
- rettv->vval.v_string = r;
-}
-
- static void
f_setcharsearch(typval_T *argvars, typval_T *rettv UNUSED)
{
dict_T *d;
diff --git a/src/main.c b/src/main.c
index 79973cbaa..e8984ee59 100644
--- a/src/main.c
+++ b/src/main.c
@@ -54,12 +54,6 @@ static void check_swap_exists_action(void);
# ifdef FEAT_EVAL
static void set_progpath(char_u *argv0);
# endif
-# if defined(FEAT_CLIENTSERVER) || defined(PROTO)
-static void exec_on_server(mparm_T *parmp);
-static void prepare_server(mparm_T *parmp);
-static void cmdsrv_main(int *argc, char **argv, char_u *serverName_arg, char_u **serverStr);
-static char_u *serverMakeName(char_u *arg, char *cmd);
-# endif
#endif
@@ -3714,670 +3708,3 @@ set_progpath(char_u *argv0)
}
#endif // NO_VIM_MAIN
-
-#if (defined(FEAT_CLIENTSERVER) && !defined(NO_VIM_MAIN)) || defined(PROTO)
-
-/*
- * Common code for the X command server and the Win32 command server.
- */
-
-static char_u *build_drop_cmd(int filec, char **filev, int tabs, int sendReply);
-
-/*
- * Do the client-server stuff, unless "--servername ''" was used.
- */
- static void
-exec_on_server(mparm_T *parmp)
-{
- if (parmp->serverName_arg == NULL || *parmp->serverName_arg != NUL)
- {
-# ifdef MSWIN
- // Initialise the client/server messaging infrastructure.
- serverInitMessaging();
-# endif
-
- /*
- * When a command server argument was found, execute it. This may
- * exit Vim when it was successful. Otherwise it's executed further
- * on. Remember the encoding used here in "serverStrEnc".
- */
- if (parmp->serverArg)
- {
- cmdsrv_main(&parmp->argc, parmp->argv,
- parmp->serverName_arg, &parmp->serverStr);
- parmp->serverStrEnc = vim_strsave(p_enc);
- }
-
- // If we're still running, get the name to register ourselves.
- // On Win32 can register right now, for X11 need to setup the
- // clipboard first, it's further down.
- parmp->servername = serverMakeName(parmp->serverName_arg,
- parmp->argv[0]);
-# ifdef MSWIN
- if (parmp->servername != NULL)
- {
- serverSetName(parmp->servername);
- vim_free(parmp->servername);
- }
-# endif
- }
-}
-
-/*
- * Prepare for running as a Vim server.
- */
- static void
-prepare_server(mparm_T *parmp)
-{
-# if defined(FEAT_X11)
- /*
- * Register for remote command execution with :serversend and --remote
- * unless there was a -X or a --servername '' on the command line.
- * Only register nongui-vim's with an explicit --servername argument,
- * or when compiling with autoservername.
- * When running as root --servername is also required.
- */
- if (X_DISPLAY != NULL && parmp->servername != NULL && (
-# if defined(FEAT_AUTOSERVERNAME) || defined(FEAT_GUI)
- (
-# if defined(FEAT_AUTOSERVERNAME)
- 1
-# else
- gui.in_use
-# endif
-# ifdef UNIX
- && getuid() != ROOT_UID
-# endif
- ) ||
-# endif
- parmp->serverName_arg != NULL))
- {
- (void)serverRegisterName(X_DISPLAY, parmp->servername);
- vim_free(parmp->servername);
- TIME_MSG("register server name");
- }
- else
- serverDelayedStartName = parmp->servername;
-# endif
-
- /*
- * Execute command ourselves if we're here because the send failed (or
- * else we would have exited above).
- */
- if (parmp->serverStr != NULL)
- {
- char_u *p;
-
- server_to_input_buf(serverConvert(parmp->serverStrEnc,
- parmp->serverStr, &p));
- vim_free(p);
- }
-}
-
- static void
-cmdsrv_main(
- int *argc,
- char **argv,
- char_u *serverName_arg,
- char_u **serverStr)
-{
- char_u *res;
- int i;
- char_u *sname;
- int ret;
- int didone = FALSE;
- int exiterr = 0;
- char **newArgV = argv + 1;
- int newArgC = 1,
- Argc = *argc;
- int argtype;
-#define ARGTYPE_OTHER 0
-#define ARGTYPE_EDIT 1
-#define ARGTYPE_EDIT_WAIT 2
-#define ARGTYPE_SEND 3
- int silent = FALSE;
- int tabs = FALSE;
-# ifndef FEAT_X11
- HWND srv;
-# else
- Window srv;
-
- setup_term_clip();
-# endif
-
- sname = serverMakeName(serverName_arg, argv[0]);
- if (sname == NULL)
- return;
-
- /*
- * Execute the command server related arguments and remove them
- * from the argc/argv array; We may have to return into main()
- */
- for (i = 1; i < Argc; i++)
- {
- res = NULL;
- if (STRCMP(argv[i], "--") == 0) // end of option arguments
- {
- for (; i < *argc; i++)
- {
- *newArgV++ = argv[i];
- newArgC++;
- }
- break;
- }
-
- if (STRICMP(argv[i], "--remote-send") == 0)
- argtype = ARGTYPE_SEND;
- else if (STRNICMP(argv[i], "--remote", 8) == 0)
- {
- char *p = argv[i] + 8;
-
- argtype = ARGTYPE_EDIT;
- while (*p != NUL)
- {
- if (STRNICMP(p, "-wait", 5) == 0)
- {
- argtype = ARGTYPE_EDIT_WAIT;
- p += 5;
- }
- else if (STRNICMP(p, "-silent", 7) == 0)
- {
- silent = TRUE;
- p += 7;
- }
- else if (STRNICMP(p, "-tab", 4) == 0)
- {
- tabs = TRUE;
- p += 4;
- }
- else
- {
- argtype = ARGTYPE_OTHER;
- break;
- }
- }
- }
- else
- argtype = ARGTYPE_OTHER;
-
- if (argtype != ARGTYPE_OTHER)
- {
- if (i == *argc - 1)
- mainerr_arg_missing((char_u *)argv[i]);
- if (argtype == ARGTYPE_SEND)
- {
- *serverStr = (char_u *)argv[i + 1];
- i++;
- }
- else
- {
- *serverStr = build_drop_cmd(*argc - i - 1, argv + i + 1,
- tabs, argtype == ARGTYPE_EDIT_WAIT);
- if (*serverStr == NULL)
- {
- // Probably out of memory, exit.
- didone = TRUE;
- exiterr = 1;
- break;
- }
- Argc = i;
- }
-# ifdef FEAT_X11
- if (xterm_dpy == NULL)
- {
- mch_errmsg(_("No display"));
- ret = -1;
- }
- else
- ret = serverSendToVim(xterm_dpy, sname, *serverStr,
- NULL, &srv, 0, 0, 0, silent);
-# else
- // Win32 always works?
- ret = serverSendToVim(sname, *serverStr, NULL, &srv, 0, 0, silent);
-# endif
- if (ret < 0)
- {
- if (argtype == ARGTYPE_SEND)
- {
- // Failed to send, abort.
- mch_errmsg(_(": Send failed.\n"));
- didone = TRUE;
- exiterr = 1;
- }
- else if (!silent)
- // Let vim start normally.
- mch_errmsg(_(": Send failed. Trying to execute locally\n"));
- break;
- }
-
-# ifdef FEAT_GUI_MSWIN
- // Guess that when the server name starts with "g" it's a GUI
- // server, which we can bring to the foreground here.
- // Foreground() in the server doesn't work very well.
- if (argtype != ARGTYPE_SEND && TOUPPER_ASC(*sname) == 'G')
- SetForegroundWindow(srv);
-# endif
-
- /*
- * For --remote-wait: Wait until the server did edit each
- * file. Also detect that the server no longer runs.
- */
- if (ret >= 0 && argtype == ARGTYPE_EDIT_WAIT)
- {
- int numFiles = *argc - i - 1;
- int j;
- char_u *done = alloc(numFiles);
- char_u *p;
-# ifdef FEAT_GUI_MSWIN
- NOTIFYICONDATA ni;
- int count = 0;
- extern HWND message_window;
-# endif
-
- if (numFiles > 0 && argv[i + 1][0] == '+')
- // Skip "+cmd" argument, don't wait for it to be edited.
- --numFiles;
-
-# ifdef FEAT_GUI_MSWIN
- ni.cbSize = sizeof(ni);
- ni.hWnd = message_window;
- ni.uID = 0;
- ni.uFlags = NIF_ICON|NIF_TIP;
- ni.hIcon = LoadIcon((HINSTANCE)GetModuleHandle(0), "IDR_VIM");
- sprintf(ni.szTip, _("%d of %d edited"), count, numFiles);
- Shell_NotifyIcon(NIM_ADD, &ni);
-# endif
-
- // Wait for all files to unload in remote
- vim_memset(done, 0, numFiles);
- while (memchr(done, 0, numFiles) != NULL)
- {
-# ifdef MSWIN
- p = serverGetReply(srv, NULL, TRUE, TRUE, 0);
- if (p == NULL)
- break;
-# else
- if (serverReadReply(xterm_dpy, srv, &p, TRUE, -1) < 0)
- break;
-# endif
- j = atoi((char *)p);
- if (j >= 0 && j < numFiles)
- {
-# ifdef FEAT_GUI_MSWIN
- ++count;
- sprintf(ni.szTip, _("%d of %d edited"),
- count, numFiles);
- Shell_NotifyIcon(NIM_MODIFY, &ni);
-# endif
- done[j] = 1;
- }
- }
-# ifdef FEAT_GUI_MSWIN
- Shell_NotifyIcon(NIM_DELETE, &ni);
-# endif
- }
- }
- else if (STRICMP(argv[i], "--remote-expr") == 0)
- {
- if (i == *argc - 1)
- mainerr_arg_missing((char_u *)argv[i]);
-# ifdef MSWIN
- // Win32 always works?
- if (serverSendToVim(sname, (char_u *)argv[i + 1],
- &res, NULL, 1, 0, FALSE) < 0)
-# else
- if (xterm_dpy == NULL)
- mch_errmsg(_("No display: Send expression failed.\n"));
- else if (serverSendToVim(xterm_dpy, sname, (char_u *)argv[i + 1],
- &res, NULL, 1, 0, 1, FALSE) < 0)
-# endif
- {
- if (res != NULL && *res != NUL)
- {
- // Output error from remote
- mch_errmsg((char *)res);
- VIM_CLEAR(res);
- }
- mch_errmsg(_(": Send expression failed.\n"));
- }
- }
- else if (STRICMP(argv[i], "--serverlist") == 0)
- {
-# ifdef MSWIN
- // Win32 always works?
- res = serverGetVimNames();
-# else
- if (xterm_dpy != NULL)
- res = serverGetVimNames(xterm_dpy);
-# endif
- if (did_emsg)
- mch_errmsg("\n");
- }
- else if (STRICMP(argv[i], "--servername") == 0)
- {
- // Already processed. Take it out of the command line
- i++;
- continue;
- }
- else
- {
- *newArgV++ = argv[i];
- newArgC++;
- continue;
- }
- didone = TRUE;
- if (res != NULL && *res != NUL)
- {
- mch_msg((char *)res);
- if (res[STRLEN(res) - 1] != '\n')
- mch_msg("\n");
- }
- vim_free(res);
- }
-
- if (didone)
- {
- display_errors(); // display any collected messages
- exit(exiterr); // Mission accomplished - get out
- }
-
- // Return back into main()
- *argc = newArgC;
- vim_free(sname);
-}
-
-/*
- * Build a ":drop" command to send to a Vim server.
- */
- static char_u *
-build_drop_cmd(
- int filec,
- char **filev,
- int tabs, // Use ":tab drop" instead of ":drop".
- int sendReply)
-{
- garray_T ga;
- int i;
- char_u *inicmd = NULL;
- char_u *p;
- char_u *cdp;
- char_u *cwd;
-
- if (filec > 0 && filev[0][0] == '+')
- {
- inicmd = (char_u *)filev[0] + 1;
- filev++;
- filec--;
- }
- // Check if we have at least one argument.
- if (filec <= 0)
- mainerr_arg_missing((char_u *)filev[-1]);
-
- // Temporarily cd to the current directory to handle relative file names.
- cwd = alloc(MAXPATHL);
- if (cwd == NULL)
- return NULL;
- if (mch_dirname(cwd, MAXPATHL) != OK)
- {
- vim_free(cwd);
- return NULL;
- }
- cdp = vim_strsave_escaped_ext(cwd,
-#ifdef BACKSLASH_IN_FILENAME
- (char_u *)"", // rem_backslash() will tell what chars to escape
-#else
- PATH_ESC_CHARS,
-#endif
- '\\', TRUE);
- vim_free(cwd);
- if (cdp == NULL)
- return NULL;
- ga_init2(&ga, 1, 100);
- ga_concat(&ga, (char_u *)"<C-\\><C-N>:cd ");
- ga_concat(&ga, cdp);
-
- // Call inputsave() so that a prompt for an encryption key works.
- ga_concat(&ga, (char_u *)"<CR>:if exists('*inputsave')|call inputsave()|endif|");
- if (tabs)
- ga_concat(&ga, (char_u *)"tab ");
- ga_concat(&ga, (char_u *)"drop");
- for (i = 0; i < filec; i++)
- {
- // On Unix the shell has already expanded the wildcards, don't want to
- // do it again in the Vim server. On MS-Windows only escape
- // non-wildcard characters.
- p = vim_strsave_escaped((char_u *)filev[i],
-#ifdef UNIX
- PATH_ESC_CHARS
-#else
- (char_u *)" \t%#"
-#endif
- );
- if (p == NULL)
- {
- vim_free(ga.ga_data);
- return NULL;
- }
- ga_concat(&ga, (char_u *)" ");
- ga_concat(&ga, p);
- vim_free(p);
- }
- ga_concat(&ga, (char_u *)"|if exists('*inputrestore')|call inputrestore()|endif<CR>");
-
- // The :drop commands goes to Insert mode when 'insertmode' is set, use
- // CTRL-\ CTRL-N again.
- ga_concat(&ga, (char_u *)"<C-\\><C-N>");
-
- // Switch back to the correct current directory (prior to temporary path
- // switch) unless 'autochdir' is set, in which case it will already be
- // correct after the :drop command. With line breaks and spaces:
- // if !exists('+acd') || !&acd
- // if haslocaldir()
- // cd -
- // lcd -
- // elseif getcwd() ==# 'current path'
- // cd -
- // endif
- // endif
- ga_concat(&ga, (char_u *)":if !exists('+acd')||!&acd|if haslocaldir()|");
- ga_concat(&ga, (char_u *)"cd -|lcd -|elseif getcwd() ==# '");
- ga_concat(&ga, cdp);
- ga_concat(&ga, (char_u *)"'|cd -|endif|endif<CR>");
- vim_free(cdp);
-
- if (sendReply)
- ga_concat(&ga, (char_u *)":call SetupRemoteReplies()<CR>");
- ga_concat(&ga, (char_u *)":");
- if (inicmd != NULL)
- {
- // Can't use <CR> after "inicmd", because an "startinsert" would cause
- // the following commands to be inserted as text. Use a "|",
- // hopefully "inicmd" does allow this...
- ga_concat(&ga, inicmd);
- ga_concat(&ga, (char_u *)"|");
- }
- // Bring the window to the foreground, goto Insert mode when 'im' set and
- // clear command line.
- ga_concat(&ga, (char_u *)"cal foreground()|if &im|star|en|redr|f<CR>");
- ga_append(&ga, NUL);
- return ga.ga_data;
-}
-
-/*
- * Make our basic server name: use the specified "arg" if given, otherwise use
- * the tail of the command "cmd" we were started with.
- * Return the name in allocated memory. This doesn't include a serial number.
- */
- static char_u *
-serverMakeName(char_u *arg, char *cmd)
-{
- char_u *p;
-
- if (arg != NULL && *arg != NUL)
- p = vim_strsave_up(arg);
- else
- {
- p = vim_strsave_up(gettail((char_u *)cmd));
- // Remove .exe or .bat from the name.
- if (p != NULL && vim_strchr(p, '.') != NULL)
- *vim_strchr(p, '.') = NUL;
- }
- return p;
-}
-#endif // FEAT_CLIENTSERVER
-
-#if defined(FEAT_CLIENTSERVER) || defined(PROTO)
-/*
- * Replace termcodes such as <CR> and insert as key presses if there is room.
- */
- void
-server_to_input_buf(char_u *str)
-{
- char_u *ptr = NULL;
- char_u *cpo_save = p_cpo;
-
- // Set 'cpoptions' the way we want it.
- // B set - backslashes are *not* treated specially
- // k set - keycodes are *not* reverse-engineered
- // < unset - <Key> sequences *are* interpreted
- // The last but one parameter of replace_termcodes() is TRUE so that the
- // <lt> sequence is recognised - needed for a real backslash.
- p_cpo = (char_u *)"Bk";
- str = replace_termcodes((char_u *)str, &ptr, REPTERM_DO_LT, NULL);
- p_cpo = cpo_save;
-
- if (*ptr != NUL) // trailing CTRL-V results in nothing
- {
- /*
- * Add the string to the input stream.
- * Can't use add_to_input_buf() here, we now have K_SPECIAL bytes.
- *
- * First clear typed characters from the typeahead buffer, there could
- * be half a mapping there. Then append to the existing string, so
- * that multiple commands from a client are concatenated.
- */
- if (typebuf.tb_maplen < typebuf.tb_len)
- del_typebuf(typebuf.tb_len - typebuf.tb_maplen, typebuf.tb_maplen);
- (void)ins_typebuf(str, REMAP_NONE, typebuf.tb_len, TRUE, FALSE);
-
- // Let input_available() know we inserted text in the typeahead
- // buffer.
- typebuf_was_filled = TRUE;
- }
- vim_free((char_u *)ptr);
-}
-
-/*
- * Evaluate an expression that the client sent to a string.
- */
- char_u *
-eval_client_expr_to_string(char_u *expr)
-{
- char_u *res;
- int save_dbl = debug_break_level;
- int save_ro = redir_off;
- funccal_entry_T funccal_entry;
- int did_save_funccal = FALSE;
-
- // Evaluate the expression at the toplevel, don't use variables local to
- // the calling function. Except when in debug mode.
- if (!debug_mode)
- {
- save_funccal(&funccal_entry);
- did_save_funccal = TRUE;
- }
-
- // Disable debugging, otherwise Vim hangs, waiting for "cont" to be
- // typed.
- debug_break_level = -1;
- redir_off = 0;
- // Do not display error message, otherwise Vim hangs, waiting for "cont"
- // to be typed. Do generate errors so that try/catch works.
- ++emsg_silent;
-
- res = eval_to_string(expr, NULL, TRUE);
-
- debug_break_level = save_dbl;
- redir_off = save_ro;
- --emsg_silent;
- if (emsg_silent < 0)
- emsg_silent = 0;
- if (did_save_funccal)
- restore_funccal();
-
- // A client can tell us to redraw, but not to display the cursor, so do
- // that here.
- setcursor();
- out_flush_cursor(FALSE, FALSE);
-
- return res;
-}
-
-/*
- * Evaluate a command or expression sent to ourselves.
- */
- int
-sendToLocalVim(char_u *cmd, int asExpr, char_u **result)
-{
- if (asExpr)
- {
- char_u *ret;
-
- ret = eval_client_expr_to_string(cmd);
- if (result != NULL)
- {
- if (ret == NULL)
- {
- char *err = _(e_invexprmsg);
- size_t len = STRLEN(cmd) + STRLEN(err) + 5;
- char_u *msg;
-
- msg = alloc(len);
- if (msg != NULL)
- vim_snprintf((char *)msg, len, "%s: \"%s\"", err, cmd);
- *result = msg;
- }
- else
- *result = ret;
- }
- else
- vim_free(ret);
- return ret == NULL ? -1 : 0;
- }
- server_to_input_buf(cmd);
- return 0;
-}
-
-/*
- * If conversion is needed, convert "data" from "client_enc" to 'encoding' and
- * return an allocated string. Otherwise return "data".
- * "*tofree" is set to the result when it needs to be freed later.
- */
- char_u *
-serverConvert(
- char_u *client_enc UNUSED,
- char_u *data,
- char_u **tofree)
-{
- char_u *res = data;
-
- *tofree = NULL;
- if (client_enc != NULL && p_enc != NULL)
- {
- vimconv_T vimconv;
-
- vimconv.vc_type = CONV_NONE;
- if (convert_setup(&vimconv, client_enc, p_enc) != FAIL
- && vimconv.vc_type != CONV_NONE)
- {
- res = string_convert(&vimconv, data, NULL);
- if (res == NULL)
- res = data;
- else
- *tofree = res;
- }
- convert_setup(&vimconv, NULL, NULL);
- }
- return res;
-}
-#endif
diff --git a/src/proto.h b/src/proto.h
index 5d8155769..0115c68d1 100644
--- a/src/proto.h
+++ b/src/proto.h
@@ -68,6 +68,7 @@ extern int _stricoll(char *a, char *b);
# include "change.pro"
# include "charset.pro"
# include "cindent.pro"
+# include "clientserver.pro"
# include "clipboard.pro"
# include "cmdexpand.pro"
# include "cmdhist.pro"
diff --git a/src/proto/clientserver.pro b/src/proto/clientserver.pro
new file mode 100644
index 000000000..3acd5e01e
--- /dev/null
+++ b/src/proto/clientserver.pro
@@ -0,0 +1,16 @@
+/* clientserver.c */
+void server_to_input_buf(char_u *str);
+char_u *eval_client_expr_to_string(char_u *expr);
+int sendToLocalVim(char_u *cmd, int asExpr, char_u **result);
+char_u *serverConvert(char_u *client_enc, char_u *data, char_u **tofree);
+void exec_on_server(mparm_T *parmp);
+void prepare_server(mparm_T *parmp);
+void f_remote_expr(typval_T *argvars, typval_T *rettv);
+void f_remote_foreground(typval_T *argvars, typval_T *rettv);
+void f_remote_peek(typval_T *argvars, typval_T *rettv);
+void f_remote_read(typval_T *argvars, typval_T *rettv);
+void f_remote_send(typval_T *argvars, typval_T *rettv);
+void f_remote_startserver(typval_T *argvars, typval_T *rettv);
+void f_server2client(typval_T *argvars, typval_T *rettv);
+void f_serverlist(typval_T *argvars, typval_T *rettv);
+/* vim: set ft=c : */
diff --git a/src/proto/main.pro b/src/proto/main.pro
index 5fa96c390..ff3e1a503 100644
--- a/src/proto/main.pro
+++ b/src/proto/main.pro
@@ -12,8 +12,4 @@ void getout_preserve_modified(int exitval);
void getout(int exitval);
int process_env(char_u *env, int is_viminit);
void mainerr_arg_missing(char_u *str);
-void server_to_input_buf(char_u *str);
-char_u *eval_client_expr_to_string(char_u *expr);
-int sendToLocalVim(char_u *cmd, int asExpr, char_u **result);
-char_u *serverConvert(char_u *client_enc, char_u *data, char_u **tofree);
/* vim: set ft=c : */
diff --git a/src/version.c b/src/version.c
index 078775ca6..fb736142d 100644
--- a/src/version.c
+++ b/src/version.c
@@ -739,6 +739,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 516,
+/**/
515,
/**/
514,