Skip to content

Instantly share code, notes, and snippets.

@ynkdir
Created March 13, 2015 06:56
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ynkdir/996d53a402f533fed518 to your computer and use it in GitHub Desktop.
Save ynkdir/996d53a402f533fed518 to your computer and use it in GitHub Desktop.
Vim clientserver without X
diff -r 15b934a16641 -r 2082fc32d223 runtime/plugin/rrhelper.vim
--- a/runtime/plugin/rrhelper.vim Wed Sep 14 19:04:40 2011 +0200
+++ b/runtime/plugin/rrhelper.vim Thu Sep 15 21:25:11 2011 +0900
@@ -16,7 +16,7 @@
let max = argc()
let id = expand("<client>")
- if id == 0
+ if id == ''
return
endif
while cnt < max
diff -r 15b934a16641 -r 2082fc32d223 src/Make_ming.mak
--- a/src/Make_ming.mak Wed Sep 14 19:04:40 2011 +0200
+++ b/src/Make_ming.mak Thu Sep 15 21:25:11 2011 +0900
@@ -466,6 +466,7 @@
$(OUTDIR)/getchar.o \
$(OUTDIR)/hardcopy.o \
$(OUTDIR)/hashtab.o \
+ $(OUTDIR)/if_cmdsrv.o \
$(OUTDIR)/main.o \
$(OUTDIR)/mark.o \
$(OUTDIR)/memfile.o \
@@ -715,6 +716,8 @@
mzscheme_base.c:
$(MZSCHEME)/mzc --c-mods mzscheme_base.c ++lib scheme/base
+$(OUTDIR)/if_cmdsrv.o: $(OUTDIR) if_cmdsrv.c if_cmdsrv_win32.c $(INCL)
+
pathdef.c: $(INCL)
ifneq (sh.exe, $(SHELL))
@echo creating pathdef.c
diff -r 15b934a16641 -r 2082fc32d223 src/Make_mvc.mak
--- a/src/Make_mvc.mak Wed Sep 14 19:04:40 2011 +0200
+++ b/src/Make_mvc.mak Thu Sep 15 21:25:11 2011 +0900
@@ -287,6 +287,10 @@
!endif
!endif
+CMDSRV_PRO = proto/if_cmdsrv.pro
+CMDSRV_OBJ = $(OBJDIR)/if_cmdsrv.obj
+CMDSRV_DEFS =
+
# Set which version of the CRT to use
!if defined(USE_MSVCRT)
# CVARS = $(cvarsdll)
@@ -321,6 +325,7 @@
CFLAGS = -c /W3 /nologo $(CVARS) -I. -Iproto -DHAVE_PATHDEF -DWIN32 \
$(SNIFF_DEFS) $(CSCOPE_DEFS) $(NETBEANS_DEFS) \
$(NBDEBUG_DEFS) $(XPM_DEFS) \
+ $(CMDSRV_DEFS) \
$(DEFINES) -DWINVER=$(WINVER) -D_WIN32_WINNT=$(WINVER) \
/Fo$(OUTDIR)/
@@ -901,12 +906,12 @@
$(VIM).exe: $(OUTDIR) $(OBJ) $(GUI_OBJ) $(OLE_OBJ) $(OLE_IDL) $(MZSCHEME_OBJ) \
$(LUA_OBJ) $(PERL_OBJ) $(PYTHON_OBJ) $(PYTHON3_OBJ) $(RUBY_OBJ) $(TCL_OBJ) \
$(SNIFF_OBJ) $(CSCOPE_OBJ) $(NETBEANS_OBJ) $(XPM_OBJ) \
- version.c version.h
+ $(CMDSRV_OBJ) version.c version.h
$(CC) $(CFLAGS) version.c
$(link) $(LINKARGS1) -out:$(VIM).exe $(OBJ) $(GUI_OBJ) $(OLE_OBJ) \
$(LUA_OBJ) $(MZSCHEME_OBJ) $(PERL_OBJ) $(PYTHON_OBJ) $(PYTHON3_OBJ) $(RUBY_OBJ) \
$(TCL_OBJ) $(SNIFF_OBJ) $(CSCOPE_OBJ) $(NETBEANS_OBJ) \
- $(XPM_OBJ) $(OUTDIR)\version.obj $(LINKARGS2)
+ $(XPM_OBJ) $(CMDSRV_OBJ) $(OUTDIR)\version.obj $(LINKARGS2)
$(VIM): $(VIM).exe
@@ -1100,6 +1105,8 @@
$(OUTDIR)/netbeans.obj: $(OUTDIR) netbeans.c $(NBDEBUG_SRC) $(INCL)
+$(OUTDIR)/if_cmdsrv.obj: $(OUTDIR) if_cmdsrv.c if_cmdsrv_win32.c $(INCL)
+
$(OUTDIR)/normal.obj: $(OUTDIR) normal.c $(INCL)
$(OUTDIR)/option.obj: $(OUTDIR) option.c $(INCL)
@@ -1229,7 +1236,8 @@
proto/ui.pro \
proto/undo.pro \
proto/window.pro \
- $(NETBEANS_PRO)
+ $(NETBEANS_PRO) \
+ $(CMDSRV_PRO)
.SUFFIXES: .cod .i
diff -r 15b934a16641 -r 2082fc32d223 src/Makefile
--- a/src/Makefile Wed Sep 14 19:04:40 2011 +0200
+++ b/src/Makefile Thu Sep 15 21:25:11 2011 +0900
@@ -1425,7 +1425,7 @@
hardcopy.c \
hashtab.c \
if_cscope.c \
- if_xcmdsrv.c \
+ if_cmdsrv.c \
main.c \
mark.c \
memfile.c \
@@ -1515,7 +1515,7 @@
objects/hashtab.o \
$(HANGULIN_OBJ) \
objects/if_cscope.o \
- objects/if_xcmdsrv.o \
+ objects/if_cmdsrv.o \
objects/mark.o \
objects/memline.o \
objects/menu.o \
@@ -1584,7 +1584,7 @@
hashtab.pro \
hangulin.pro \
if_cscope.pro \
- if_xcmdsrv.pro \
+ if_cmdsrv.pro \
if_python.pro \
if_python3.pro \
if_ruby.pro \
@@ -2531,8 +2531,8 @@
objects/if_cscope.o: if_cscope.c
$(CCC) -o $@ if_cscope.c
-objects/if_xcmdsrv.o: if_xcmdsrv.c
- $(CCC) -o $@ if_xcmdsrv.c
+objects/if_cmdsrv.o: if_cmdsrv.c
+ $(CCC) -o $@ if_cmdsrv.c
objects/if_lua.o: if_lua.c
$(CCC) $(LUA_CFLAGS) -o $@ if_lua.c
@@ -2852,10 +2852,10 @@
auto/osdef.h ascii.h keymap.h term.h macros.h option.h structs.h \
regexp.h gui.h gui_beval.h proto/gui_beval.pro ex_cmds.h proto.h \
globals.h farsi.h arabic.h if_cscope.h
-objects/if_xcmdsrv.o: if_xcmdsrv.c vim.h auto/config.h feature.h os_unix.h \
+objects/if_cmdsrv.o: if_cmdsrv.c vim.h auto/config.h feature.h os_unix.h \
auto/osdef.h ascii.h keymap.h term.h macros.h option.h structs.h \
regexp.h gui.h gui_beval.h proto/gui_beval.pro ex_cmds.h proto.h \
- globals.h farsi.h arabic.h version.h
+ globals.h farsi.h arabic.h version.h if_cmdsrv_unix.c
objects/main.o: main.c vim.h auto/config.h feature.h os_unix.h auto/osdef.h \
ascii.h keymap.h term.h macros.h option.h structs.h regexp.h gui.h \
gui_beval.h proto/gui_beval.pro ex_cmds.h proto.h globals.h farsi.h \
diff -r 15b934a16641 -r 2082fc32d223 src/charset.c
--- a/src/charset.c Wed Sep 14 19:04:40 2011 +0200
+++ b/src/charset.c Thu Sep 15 21:25:11 2011 +0900
@@ -1897,7 +1897,7 @@
return c - '0';
}
-#if defined(FEAT_TERMRESPONSE) \
+#if defined(FEAT_TERMRESPONSE) || defined(FEAT_CLIENTSERVER) \
|| (defined(FEAT_GUI_GTK) && defined(FEAT_WINDOWS)) || defined(PROTO)
/*
* Convert two hex characters to a byte.
diff -r 15b934a16641 -r 2082fc32d223 src/config.h.in
--- a/src/config.h.in Wed Sep 14 19:04:40 2011 +0200
+++ b/src/config.h.in Thu Sep 15 21:25:11 2011 +0900
@@ -210,6 +210,8 @@
#undef HAVE_USLEEP
#undef HAVE_UTIME
#undef HAVE_BIND_TEXTDOMAIN_CODESET
+#undef HAVE_GETPEERUCRED
+#undef HAVE_GETPEEREID
/* Define, if needed, for accessing large files. */
#undef _LARGE_FILES
diff -r 15b934a16641 -r 2082fc32d223 src/configure.in
--- a/src/configure.in Wed Sep 14 19:04:40 2011 +0200
+++ b/src/configure.in Thu Sep 15 21:25:11 2011 +0900
@@ -2973,7 +2973,7 @@
setpgid setsid sigaltstack sigstack sigset sigsetjmp sigaction \
sigvec strcasecmp strerror strftime stricmp strncasecmp \
strnicmp strpbrk strtol tgetent towlower towupper iswupper \
- usleep utime utimes)
+ usleep utime utimes getpeerucred getpeereid)
AC_FUNC_FSEEKO
dnl define _LARGE_FILES, _FILE_OFFSET_BITS and _LARGEFILE_SOURCE when
diff -r 15b934a16641 -r 2082fc32d223 src/eval.c
--- a/src/eval.c Wed Sep 14 19:04:40 2011 +0200
+++ b/src/eval.c Thu Sep 15 21:25:11 2011 +0900
@@ -14535,38 +14535,6 @@
#endif
}
-#if defined(FEAT_CLIENTSERVER) && defined(FEAT_X11)
-static void make_connection __ARGS((void));
-static int check_connection __ARGS((void));
-
- static void
-make_connection()
-{
- 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()
-{
- make_connection();
- if (X_DISPLAY == NULL)
- {
- EMSG(_("E240: No connection to Vim server"));
- return FAIL;
- }
- return OK;
-}
-#endif
-
#ifdef FEAT_CLIENTSERVER
static void remote_common __ARGS((typval_T *argvars, typval_T *rettv, int expr));
@@ -14576,39 +14544,42 @@
typval_T *rettv;
int expr;
{
- char_u *server_name;
+ char_u *name;
char_u *keys;
+ char_u *serverid;
char_u *r = NULL;
char_u buf[NUMBUFLEN];
-# ifdef WIN32
- HWND w;
-# else
- Window w;
-# endif
+ int ret;
if (check_restricted() || check_secure())
return;
-# ifdef FEAT_X11
- if (check_connection() == FAIL)
- return;
-# endif
-
- server_name = get_tv_string_chk(&argvars[0]);
- if (server_name == NULL)
+ name = get_tv_string_chk(&argvars[0]);
+ if (name == NULL)
return; /* type error; errmsg already given */
keys = get_tv_string_buf(&argvars[1], buf);
-# ifdef WIN32
- if (serverSendToVim(server_name, keys, &r, &w, expr, TRUE) < 0)
-# else
- if (serverSendToVim(X_DISPLAY, server_name, keys, &r, &w, expr, 0, TRUE)
- < 0)
-# endif
+
+ serverid = cmdsrv_find_server(name, TRUE);
+ if (serverid == NULL)
+ {
+ ret = -1;
+ }
+ else
+ {
+ if (expr)
+ ret = cmdsrv_send_expr(serverid, keys, &r);
+ else
+ ret = cmdsrv_send_keys(serverid, keys);
+ }
+
+ if (ret != 0)
{
if (r != NULL)
EMSG(r); /* sending worked but evaluation failed */
else
- EMSG2(_("E241: Unable to send to %s"), server_name);
+ EMSG2(_(e_unabletosend), name);
+ vim_free(r);
+ vim_free(serverid);
return;
}
@@ -14617,17 +14588,20 @@
if (argvars[2].v_type != VAR_UNKNOWN)
{
dictitem_T v;
- char_u str[30];
char_u *idvar;
- 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);
+ if (serverid == NULL)
+ v.di_tv.vval.v_string = vim_strsave((char_u *)"");
+ else
+ v.di_tv.vval.v_string = vim_strsave(serverid);
idvar = get_tv_string_chk(&argvars[2]);
if (idvar != NULL)
set_var(idvar, &v.di_tv, FALSE);
vim_free(v.di_tv.vval.v_string);
}
+
+ vim_free(serverid);
}
#endif
@@ -14655,22 +14629,26 @@
typval_T *rettv UNUSED;
{
#ifdef FEAT_CLIENTSERVER
-# ifdef WIN32
- /* On Win32 it's done in this application. */
- {
- char_u *server_name = get_tv_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;
- remote_common(argvars, rettv, TRUE);
- vim_free(argvars[1].vval.v_string);
-# endif
+ char_u *name;
+ char_u *serverid;
+
+ name = get_tv_string_chk(&argvars[0]);
+ if (name == NULL)
+ return;
+
+ serverid = cmdsrv_find_server(name, TRUE);
+ if (serverid == NULL)
+ {
+ EMSG2(_(e_unabletosend), name);
+ return;
+ }
+
+ if (cmdsrv_foreground(serverid) != 0)
+ {
+ EMSG2(_(e_unabletosend), name);
+ }
+
+ vim_free(serverid);
#endif
}
@@ -14682,9 +14660,6 @@
#ifdef FEAT_CLIENTSERVER
dictitem_T v;
char_u *s = NULL;
-# ifdef WIN32
- long_u n = 0;
-# endif
char_u *serverid;
if (check_restricted() || check_secure())
@@ -14698,22 +14673,13 @@
rettv->vval.v_number = -1;
return; /* type error; errmsg already given */
}
-# ifdef WIN32
- sscanf(serverid, SCANF_HEX_LONG_U, &n);
- if (n == 0)
+
+ if (cmdsrv_peek_reply(serverid, &s) != 0)
rettv->vval.v_number = -1;
- else
- {
- s = serverGetReply((HWND)n, FALSE, FALSE, FALSE);
- rettv->vval.v_number = (s != NULL);
- }
-# else
- if (check_connection() == FAIL)
- return;
-
- rettv->vval.v_number = serverPeekReply(X_DISPLAY,
- serverStrToWin(serverid), &s);
-# endif
+ else if (s != NULL)
+ rettv->vval.v_number = 1;
+ else
+ rettv->vval.v_number = 0;
if (argvars[1].v_type != VAR_UNKNOWN && rettv->vval.v_number > 0)
{
@@ -14743,18 +14709,7 @@
if (serverid != NULL && !check_restricted() && !check_secure())
{
-# ifdef WIN32
- /* The server's HWND is encoded in the 'id' parameter */
- long_u n = 0;
-
- sscanf(serverid, SCANF_HEX_LONG_U, &n);
- if (n != 0)
- r = serverGetReply((HWND)n, FALSE, TRUE, TRUE);
- if (r == NULL)
-# else
- if (check_connection() == FAIL || serverReadReply(X_DISPLAY,
- serverStrToWin(serverid), &r, FALSE) < 0)
-# endif
+ if (cmdsrv_wait_reply(serverid, &r) != 0)
EMSG(_("E277: Unable to read a server reply"));
}
#endif
@@ -15722,20 +15677,16 @@
{
#ifdef FEAT_CLIENTSERVER
char_u buf[NUMBUFLEN];
- char_u *server = get_tv_string_chk(&argvars[0]);
+ char_u *serverid = get_tv_string_chk(&argvars[0]);
char_u *reply = get_tv_string_buf_chk(&argvars[1], buf);
rettv->vval.v_number = -1;
- if (server == NULL || reply == NULL)
+ if (serverid == NULL || reply == NULL)
return;
if (check_restricted() || check_secure())
return;
-# ifdef FEAT_X11
- if (check_connection() == FAIL)
- return;
-# endif
-
- if (serverSendReply(server, reply) < 0)
+
+ if (cmdsrv_send_notification(serverid, reply) < 0)
{
EMSG(_("E258: Unable to send to client"));
return;
@@ -15754,14 +15705,9 @@
char_u *r = NULL;
#ifdef FEAT_CLIENTSERVER
-# ifdef WIN32
- r = serverGetVimNames();
-# else
- make_connection();
- if (X_DISPLAY != NULL)
- r = serverGetVimNames(X_DISPLAY);
-# endif
-#endif
+ cmdsrv_server_list(&r);
+#endif
+
rettv->v_type = VAR_STRING;
rettv->vval.v_string = r;
}
diff -r 15b934a16641 -r 2082fc32d223 src/ex_docmd.c
--- a/src/ex_docmd.c Wed Sep 14 19:04:40 2011 +0200
+++ b/src/ex_docmd.c Thu Sep 15 21:25:11 2011 +0900
@@ -9855,9 +9855,9 @@
break;
#if defined(FEAT_CLIENTSERVER)
case SPEC_CLIENT: /* Source of last submitted input */
- sprintf((char *)strbuf, PRINTF_HEX_LONG_U,
- (long_u)clientWindow);
- result = strbuf;
+ result = cmdsrv_clientid;
+ if (result == NULL)
+ result = (char_u *)"";
break;
#endif
}
diff -r 15b934a16641 -r 2082fc32d223 src/feature.h
--- a/src/feature.h Wed Sep 14 19:04:40 2011 +0200
+++ b/src/feature.h Thu Sep 15 21:25:11 2011 +0900
@@ -1125,7 +1125,7 @@
* +clientserver Remote control via the remote_send() function
* and the --remote argument
*/
-#if (defined(WIN32) || defined(FEAT_XCLIPBOARD)) && defined(FEAT_EVAL)
+#if (defined(WIN32) || defined(UNIX)) && defined(FEAT_EVAL)
# define FEAT_CLIENTSERVER
#endif
diff -r 15b934a16641 -r 2082fc32d223 src/getchar.c
--- a/src/getchar.c Wed Sep 14 19:04:40 2011 +0200
+++ b/src/getchar.c Thu Sep 15 21:25:11 2011 +0900
@@ -2954,6 +2954,10 @@
netbeans_parse_messages();
#endif
+#if defined(FEAT_CLIENTSERVER)
+ cmdsrv_handle_requests();
+#endif
+
if (got_int || (script_char = getc(scriptin[curscript])) < 0)
{
/* Reached EOF.
diff -r 15b934a16641 -r 2082fc32d223 src/globals.h
--- a/src/globals.h Wed Sep 14 19:04:40 2011 +0200
+++ b/src/globals.h Thu Sep 15 21:25:11 2011 +0900
@@ -203,11 +203,6 @@
#endif
#if (defined(UNIX) || defined(VMS)) && defined(FEAT_X11)
EXTERN int x_no_connect INIT(= FALSE); /* don't connect to X server */
-# if defined(FEAT_CLIENTSERVER)
-EXTERN int x_force_connect INIT(= FALSE); /* Do connect to X server.
- Overrules x_no_connect and
- "exclude" in 'clipboard'. */
-# endif
#endif
EXTERN int ex_keep_indent INIT(= FALSE); /* getexmodeline(): keep indent */
EXTERN int vgetc_busy INIT(= 0); /* when inside vgetc() then > 0 */
@@ -1300,17 +1295,18 @@
#ifdef FEAT_CLIENTSERVER
EXTERN char_u *serverName INIT(= NULL); /* name of the server */
-# ifdef FEAT_X11
-EXTERN Window commWindow INIT(= None);
-EXTERN Window clientWindow INIT(= None);
-EXTERN Atom commProperty INIT(= None);
-EXTERN char_u *serverDelayedStartName INIT(= NULL);
+EXTERN char_u *cmdsrv_clientid INIT(= NULL); /* Source of last
+ submitted input */
+# ifdef WIN3264
+EXTERN HANDLE *cmdsrv_events INIT(= NULL); /* network events */
# else
-# ifdef PROTO
-typedef int HWND;
+EXTERN int cmdsrv_listenfd INIT(= -1); /* server socket */
# endif
-EXTERN HWND clientWindow INIT(= 0);
-# endif
+/* The maximum length of the pending connections queue.
+ * For win32, length of cmdsrv_events */
+# define CMDSRV_INSTANCES 5
+/* Temporary server name to receive --remote-wait response */
+# define CMDSRV_TMPNAME "tmp"
#endif
#if defined(UNIX) || defined(VMS)
@@ -1468,6 +1464,7 @@
EXTERN char_u e_noroom[] INIT(= N_("E36: Not enough room"));
#endif
#ifdef FEAT_CLIENTSERVER
+EXTERN char_u e_unabletosend[] INIT(= N_("E241: Unable to send to %s"));
EXTERN char_u e_noserver[] INIT(= N_("E247: no registered server named \"%s\""));
#endif
EXTERN char_u e_notcreate[] INIT(= N_("E482: Can't create file %s"));
diff -r 15b934a16641 -r 2082fc32d223 src/gui.c
--- a/src/gui.c Wed Sep 14 19:04:40 2011 +0200
+++ b/src/gui.c Thu Sep 15 21:25:11 2011 +0900
@@ -747,6 +747,10 @@
if (p_ch != 1L)
command_height();
+#ifdef FEAT_CLIENTSERVER
+ cmdsrv_gui_register();
+#endif
+
return;
}
@@ -766,6 +770,9 @@
gui_exit(rc)
int rc;
{
+#ifdef FEAT_CLIENTSERVER
+ cmdsrv_gui_unregister();
+#endif
#ifndef __BEOS__
/* don't free the fonts, it leads to a BUS error
* richard@whitequeen.com Jul 99 */
@@ -4933,6 +4940,10 @@
#ifdef FEAT_NETBEANS_INTG
netbeans_gui_register();
#endif
+#ifdef FEAT_CLIENTSERVER
+ /* TODO: unnecessary? */
+ cmdsrv_gui_register();
+#endif
}
if (!ends_excmd(*eap->arg))
ex_next(eap);
diff -r 15b934a16641 -r 2082fc32d223 src/gui_gtk_x11.c
--- a/src/gui_gtk_x11.c Wed Sep 14 19:04:40 2011 +0200
+++ b/src/gui_gtk_x11.c Thu Sep 15 21:25:11 2011 +0900
@@ -629,33 +629,6 @@
return FALSE;
}
-#ifdef FEAT_CLIENTSERVER
-/*
- * Handle changes to the "Comm" property
- */
- static gint
-property_event(GtkWidget *widget,
- GdkEventProperty *event,
- gpointer data UNUSED)
-{
- if (event->type == GDK_PROPERTY_NOTIFY
- && event->state == (int)GDK_PROPERTY_NEW_VALUE
- && GDK_WINDOW_XWINDOW(event->window) == commWindow
- && GET_X_ATOM(event->atom) == commProperty)
- {
- XEvent xev;
-
- /* Translate to XLib */
- xev.xproperty.type = PropertyNotify;
- xev.xproperty.atom = commProperty;
- xev.xproperty.window = commWindow;
- xev.xproperty.state = PropertyNewValue;
- serverEventProc(GDK_WINDOW_XDISPLAY(widget->window), &xev);
- }
- return FALSE;
-}
-#endif
-
/****************************************************************************
* Focus handlers:
@@ -2367,30 +2340,6 @@
if (using_gnome)
#endif
setup_save_yourself();
-
-#ifdef FEAT_CLIENTSERVER
- if (serverName == NULL && serverDelayedStartName != NULL)
- {
- /* This is a :gui command in a plain vim with no previous server */
- commWindow = GDK_WINDOW_XWINDOW(gui.mainwin->window);
-
- (void)serverRegisterName(GDK_WINDOW_XDISPLAY(gui.mainwin->window),
- serverDelayedStartName);
- }
- else
- {
- /*
- * Cannot handle "XLib-only" windows with gtk event routines, we'll
- * have to change the "server" registration to that of the main window
- * If we have not registered a name yet, remember the window
- */
- serverChangeRegisteredWindow(GDK_WINDOW_XDISPLAY(gui.mainwin->window),
- GDK_WINDOW_XWINDOW(gui.mainwin->window));
- }
- gtk_widget_add_events(gui.mainwin, GDK_PROPERTY_CHANGE_MASK);
- gtk_signal_connect(GTK_OBJECT(gui.mainwin), "property_notify_event",
- GTK_SIGNAL_FUNC(property_event), NULL);
-#endif
}
static GdkCursor *
@@ -5155,8 +5104,7 @@
}
#endif
-#if defined(FEAT_CLIENTSERVER) \
- || (defined(FEAT_X11) && defined(FEAT_CLIPBOARD)) || defined(PROTO)
+#if (defined(FEAT_X11) && defined(FEAT_CLIPBOARD)) || defined(PROTO)
Display *
gui_mch_get_display(void)
@@ -5431,6 +5379,10 @@
netbeans_parse_messages();
#endif
+#if defined(FEAT_CLIENTSERVER)
+ cmdsrv_handle_requests();
+#endif
+
/*
* Loop in GTK+ processing until a timeout or input occurs.
* Skip this if input is available anyway (can happen in rare
diff -r 15b934a16641 -r 2082fc32d223 src/gui_w48.c
--- a/src/gui_w48.c Wed Sep 14 19:04:40 2011 +0200
+++ b/src/gui_w48.c Thu Sep 15 21:25:11 2011 +0900
@@ -301,8 +301,6 @@
static int s_x_pending;
static int s_y_pending;
static UINT s_kFlags_pending;
-static UINT s_wait_timer = 0; /* Timer for get char from user */
-static int s_timed_out = FALSE;
static int dead_key = 0; /* 0 - no dead key, 1 - dead key pressed */
#ifdef WIN3264
@@ -460,29 +458,6 @@
*/
/*ARGSUSED*/
- static VOID CALLBACK
-_OnTimer(
- HWND hwnd,
- UINT uMsg,
- UINT idEvent,
- DWORD dwTime)
-{
- MSG msg;
-
- /*
- TRACE2("Got timer event, id %d, s_wait_timer %d\n", idEvent, s_wait_timer);
- */
- KillTimer(NULL, idEvent);
- s_timed_out = TRUE;
-
- /* Eat spurious WM_TIMER messages */
- while (pPeekMessage(&msg, hwnd, WM_TIMER, WM_TIMER, PM_REMOVE))
- ;
- if (idEvent == s_wait_timer)
- s_wait_timer = 0;
-}
-
-/*ARGSUSED*/
static void
_OnDeadChar(
HWND hwnd,
@@ -1960,24 +1935,41 @@
int
gui_mch_wait_for_chars(int wtime)
{
- MSG msg;
int focus;
-
- s_timed_out = FALSE;
+ DWORD starttime;
+ DWORD lefttime;
+ DWORD waittime;
+ DWORD dwwait;
+#ifdef FEAT_CLIENTSERVER
+ HANDLE wait_objects[CMDSRV_INSTANCES];
+#else
+ HANDLE wait_objects[1]; /* dummy */
+#endif
+ int wait_nitems = 0;
if (wtime > 0)
{
/* Don't do anything while processing a (scroll) message. */
if (s_busy_processing)
return FAIL;
- s_wait_timer = (UINT)SetTimer(NULL, 0, (UINT)wtime,
- (TIMERPROC)_OnTimer);
}
+#ifdef FEAT_CLIENTSERVER
+ if (cmdsrv_events != NULL)
+ {
+ mch_memmove(wait_objects + wait_nitems, cmdsrv_events,
+ sizeof(HANDLE) * CMDSRV_INSTANCES);
+ wait_nitems += CMDSRV_INSTANCES;
+ }
+#endif
+
allow_scrollbar = TRUE;
focus = gui.in_focus;
- while (!s_timed_out)
+
+ starttime = GetTickCount();
+
+ for (;;)
{
/* Stop or start blinking when focus changes */
if (gui.in_focus != focus)
@@ -1999,42 +1991,57 @@
s_need_activate = FALSE;
}
+ /* Process the queued messages. */
+ gui_mch_update();
+ if (input_available())
+ break;
+
#ifdef FEAT_NETBEANS_INTG
/* Process the queued netbeans messages. */
netbeans_parse_messages();
+ if (input_available())
+ break;
#endif
- /*
- * Don't use gui_mch_update() because then we will spin-lock until a
- * char arrives, instead we use GetMessage() to hang until an
- * event arrives. No need to check for input_buf_full because we are
- * returning as soon as it contains a single char -- webb
- */
- process_message();
-
+#if defined(FEAT_CLIENTSERVER)
+ /* Process the pending clientserver request. */
+ cmdsrv_handle_requests();
if (input_available())
- {
- if (s_wait_timer != 0 && !s_timed_out)
- {
- KillTimer(NULL, s_wait_timer);
-
- /* Eat spurious WM_TIMER messages */
- while (pPeekMessage(&msg, s_hwnd, WM_TIMER, WM_TIMER, PM_REMOVE))
- ;
- s_wait_timer = 0;
- }
- allow_scrollbar = FALSE;
-
- /* Clear pending mouse button, the release event may have been
- * taken by the dialog window. But don't do this when getting
- * focus, we need the mouse-up event then. */
- if (!s_getting_focus)
- s_button_pending = -1;
-
- return OK;
- }
+ break;
+#endif
+
+ lefttime = GetTickCount() - starttime;
+ if (wtime == 0)
+ break;
+ else if (wtime > 0 && (DWORD)wtime <= lefttime)
+ break;
+
+ /* Wait messages and objects. */
+ if (wtime < 0)
+ waittime = INFINITE;
+ else
+ waittime = wtime - lefttime;
+ dwwait = MsgWaitForMultipleObjects(wait_nitems, wait_objects,
+ FALSE, waittime, QS_ALLINPUT);
+ if (dwwait == WAIT_FAILED)
+ break;
+ else if (dwwait == WAIT_TIMEOUT)
+ break;
}
+
allow_scrollbar = FALSE;
+
+ if (input_available())
+ {
+ /* Clear pending mouse button, the release event may have been
+ * taken by the dialog window. But don't do this when getting
+ * focus, we need the mouse-up event then. */
+ if (!s_getting_focus)
+ s_button_pending = -1;
+
+ return OK;
+ }
+
return FAIL;
}
diff -r 15b934a16641 -r 2082fc32d223 src/gui_x11.c
--- a/src/gui_x11.c Wed Sep 14 19:04:40 2011 +0200
+++ b/src/gui_x11.c Thu Sep 15 21:25:11 2011 +0900
@@ -149,9 +149,6 @@
static void gui_x11_sniff_request_cb __ARGS((XtPointer closure, int *source, XtInputId *id));
#endif
static void gui_x11_check_copy_area __ARGS((void));
-#ifdef FEAT_CLIENTSERVER
-static void gui_x11_send_event_handler __ARGS((Widget, XtPointer, XEvent *, Boolean *));
-#endif
static void gui_x11_wm_protocol_handler __ARGS((Widget, XtPointer, XEvent *, Boolean *));
static void gui_x11_blink_cb __ARGS((XtPointer timed_out, XtIntervalId *interval_id));
static Cursor gui_x11_create_blank_mouse __ARGS((void));
@@ -1643,27 +1640,6 @@
(XtPointer)NULL);
#endif
-#ifdef FEAT_CLIENTSERVER
- if (serverName == NULL && serverDelayedStartName != NULL)
- {
- /* This is a :gui command in a plain vim with no previous server */
- commWindow = XtWindow(vimShell);
- (void)serverRegisterName(gui.dpy, serverDelayedStartName);
- }
- else
- {
- /*
- * Cannot handle "widget-less" windows with XtProcessEvent() we'll
- * have to change the "server" registration to that of the main window
- * If we have not registered a name yet, remember the window
- */
- serverChangeRegisteredWindow(gui.dpy, XtWindow(vimShell));
- }
- XtAddEventHandler(vimShell, PropertyChangeMask, False,
- gui_x11_send_event_handler, NULL);
-#endif
-
-
#if defined(FEAT_MENU) && defined(FEAT_GUI_ATHENA)
/* The Athena GUI needs this again after opening the window */
gui_position_menu();
@@ -2900,6 +2876,10 @@
netbeans_parse_messages();
#endif
+#if defined(FEAT_CLIENTSERVER)
+ cmdsrv_handle_requests();
+#endif
+
/*
* Don't use gui_mch_update() because then we will spin-lock until a
* char arrives, instead we use XtAppProcessEvent() to hang until an
@@ -3183,27 +3163,6 @@
gui_shell_closed();
}
-#ifdef FEAT_CLIENTSERVER
-/*
- * Function called when property changed. Check for incoming commands
- */
- static void
-gui_x11_send_event_handler(w, client_data, event, dum)
- Widget w UNUSED;
- XtPointer client_data UNUSED;
- XEvent *event;
- Boolean *dum UNUSED;
-{
- XPropertyEvent *e = (XPropertyEvent *) event;
-
- if (e->type == PropertyNotify && e->window == commWindow
- && e->atom == commProperty && e->state == PropertyNewValue)
- {
- serverEventProc(gui.dpy, event);
- }
-}
-#endif
-
/*
* Cursor blink functions.
*
diff -r 15b934a16641 -r 2082fc32d223 src/if_cmdsrv.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/if_cmdsrv.c Thu Sep 15 21:25:11 2011 +0900
@@ -0,0 +1,1198 @@
+/*
+ * TODO:
+ * document
+ *
+ * error message
+ *
+ * Use inet socket?
+ *
+ * test
+ *
+ * unix: How to automatically remove socket file which is not listened
+ * (i.e. vim crashed)? To test with connect() makes many connections
+ * and it may cause EAGAIN error with following connect(). No need to
+ * do it?
+ *
+ *
+ * Changed:
+ *
+ * - unix: use unix domain socket.
+ * /tmp/vim-cmdsrv-<uid>/<serverid>
+ *
+ * - win32: use named pipe.
+ * \\.\pipe\vim-cmdsrv-<serverid>
+ *
+ * - expand('<client>') returns server name instead of number.
+ *
+ */
+
+/* for struct ucred */
+#ifdef __linux__
+# define _GNU_SOURCE
+#endif
+
+#include "vim.h"
+#include "version.h"
+
+#if defined(FEAT_CLIENTSERVER) || defined(PROTO)
+
+#ifdef WIN3264
+# include "if_cmdsrv_win32.c"
+#else
+# include "if_cmdsrv_unix.c"
+#endif
+
+typedef struct
+{
+ char_u *type;
+ char_u *sender;
+ char_u *script;
+ char_u *reply;
+ char_u *code;
+ char_u *encoding;
+ int ncode;
+} cmdsrv_message_T;
+
+typedef struct
+{
+ char_u *serverid;
+ garray_T strings;
+} cmdsrv_server_reply_T;
+
+static garray_T cmdsrv_reply = GA_EMPTY;
+
+static int cmdsrv_is_serial_name(char_u *name);
+static cmdsrv_server_reply_T *cmdsrv_reply_find(char_u *serverid);
+static int cmdsrv_reply_add(char_u *serverid, char_u *str);
+static int cmdsrv_reply_delete(char_u *serverid);
+static int cmdsrv_msg_keys(char_u *keys, char_u **abuf, size_t *abufsize);
+static int cmdsrv_msg_expr(char_u *expr, char_u **abuf, size_t *abufsize);
+static int cmdsrv_msg_reply(char_u *reply, int code, char_u **abuf, size_t *abufsize);
+static int cmdsrv_msg_notification(char_u *reply, char_u **abuf, size_t *abufsize);
+static int cmdsrv_parse_message(char_u *msg, cmdsrv_message_T *result);
+static int cmdsrv_receive_keys(cmdsrv_handle_t conn, cmdsrv_message_T *pmsg);
+static int cmdsrv_receive_expr(cmdsrv_handle_t conn, cmdsrv_message_T *pmsg);
+static int cmdsrv_receive_notification(cmdsrv_handle_t conn, cmdsrv_message_T *pmsg);
+static char_u *cmdsrv_convert(char_u *client_enc, char_u *data);
+
+static cmdsrv_handle_t cmdsrv_server = NULL;
+
+#ifdef FEAT_GUI
+# define CMDSRV_HAS_GUI (gui.in_use || gui.starting)
+# if defined(FEAT_GUI_X11)
+# define CMDSRV_OPEN (cmdsrv_listenfd != -1)
+static void cmdsrv_message_from_client(XtPointer clientData, int *unused1, XtInputId *unused2);
+static XtInputId inputHandler = (XtInputId)NULL;
+# elif defined(FEAT_GUI_GTK)
+# define CMDSRV_OPEN (cmdsrv_listenfd != -1)
+static void cmdsrv_message_from_client(gpointer clientData, gint unused1, GdkInputCondition unused2);
+static gint inputHandler = 0;
+# elif defined(FEAT_GUI_W32)
+# define CMDSRV_OPEN (cmdsrv_events != NULL)
+# endif
+#endif
+
+#define CMDSRV_SEND_MSEC_POLL 50
+
+int
+cmdsrv_init(void)
+{
+ ga_init2(&cmdsrv_reply, sizeof(cmdsrv_server_reply_T), 1);
+
+ return 0;
+}
+
+int
+cmdsrv_uninit(void)
+{
+ cmdsrv_server_reply_T *p;
+ int i;
+
+ if (cmdsrv_server == NULL)
+ return 0;
+
+ vim_free(serverName);
+ serverName = NULL;
+
+ vim_free(cmdsrv_clientid);
+ cmdsrv_clientid = NULL;
+
+ if (cmdsrv_serv_close(cmdsrv_server) != 0)
+ return -1;
+
+ cmdsrv_server = NULL;
+
+ p = (cmdsrv_server_reply_T *)cmdsrv_reply.ga_data;
+ for (i = 0; i < cmdsrv_reply.ga_len; ++i)
+ {
+ vim_free(p[i].serverid);
+ ga_clear(&p[i].strings);
+ }
+ ga_clear(&cmdsrv_reply);
+
+ return 0;
+}
+
+#ifdef FEAT_GUI
+int
+cmdsrv_gui_register(void)
+{
+ if (!CMDSRV_HAS_GUI || !CMDSRV_OPEN)
+ return 0;
+
+#if defined(FEAT_GUI_X11)
+ if (inputHandler == (XtInputId)NULL)
+ {
+ inputHandler = XtAppAddInput(
+ (XtAppContext)app_context,
+ cmdsrv_listenfd,
+ (XtPointer)(XtInputReadMask + XtInputExceptMask),
+ cmdsrv_message_from_client,
+ NULL);
+ }
+#elif defined(FEAT_GUI_GTK)
+ if (inputHandler == 0)
+ {
+ inputHandler = gdk_input_add(
+ (gint)cmdsrv_listenfd,
+ (GdkInputCondition)((int)GDK_INPUT_READ
+ + (int)GDK_INPUT_EXCEPTION),
+ cmdsrv_message_from_client,
+ NULL);
+ }
+#endif
+
+ return 0;
+}
+
+int
+cmdsrv_gui_unregister(void)
+{
+#if defined(FEAT_GUI_X11)
+ if (inputHandler != (XtInputId)NULL)
+ {
+ XtRemoveInput(inputHandler);
+ inputHandler = (XtInputId)NULL;
+ }
+#elif defined(FEAT_GUI_GTK)
+ if (inputHandler != 0)
+ {
+ gdk_input_remove(inputHandler);
+ inputHandler = 0;
+ }
+#endif
+
+ return 0;
+}
+#endif
+
+int
+cmdsrv_register_name(char_u *name)
+{
+ cmdsrv_handle_t server = NULL;
+ char_u *serverid = NULL;
+ int i;
+
+ serverid = alloc(STRLEN(name) + 3 + 1); /* name + 1-999 + NUL */
+ if (serverid == NULL)
+ return -1;
+
+ STRCPY(serverid, name);
+
+ if (cmdsrv_serv_listen(serverid, &server) != 0)
+ {
+ /* Specified name is not available. Try to register with postfix. */
+ /* XXX: For backward compatibility, try loosename even if the
+ * specified name is serial name (name[0-999]). */
+ for (i = 1; i < 1000; ++i)
+ {
+ sprintf((char *)serverid, "%s%d", name, i);
+ if (cmdsrv_serv_listen(serverid, &server) == 0)
+ break;
+ }
+ }
+
+ if (server == NULL)
+ {
+ MSG_ATTR(_("Unable to register a command server name"),
+ hl_attr(HLF_W));
+ vim_free(serverid);
+ return -1;
+ }
+
+ serverName = strup_save(serverid);
+ if (serverName == NULL)
+ {
+ vim_free(serverid);
+ cmdsrv_serv_close(server);
+ return -1;
+ }
+
+#ifdef FEAT_EVAL
+ set_vim_var_string(VV_SEND_SERVER, serverName, -1);
+#endif
+
+#ifdef FEAT_TITLE
+ need_maketitle = TRUE;
+#endif
+
+ vim_free(serverid);
+
+ cmdsrv_server = server;
+
+ return 0;
+}
+
+int
+cmdsrv_server_list(char_u **result)
+{
+ garray_T ga;
+ char_u *list;
+ char_u *p;
+
+ list = cmdsrv_list(NUL);
+ if (list == NULL)
+ return -1;
+
+ ga_init2(&ga, (int)sizeof(char), 100);
+
+ /* filter temporary server name */
+ for (p = list; *p != NUL; p += STRLEN(p) + 1)
+ {
+ if (STRNICMP(p, CMDSRV_TMPNAME, STRLEN(CMDSRV_TMPNAME)) != 0)
+ {
+ ga_concat(&ga, p);
+ ga_append(&ga, '\n');
+ }
+ }
+
+ ga_append(&ga, NUL);
+
+ vim_free(list);
+
+ *result = ga.ga_data;
+
+ return 0;
+}
+
+/*
+ * @param timeoutmsec -1 infinit, 0 nowait, >0 millisecond
+ * @return -1 error, 0 timeout, 1 received (not handled yet)
+ */
+int
+cmdsrv_wait_request(int timeoutmsec)
+{
+ if (cmdsrv_server == NULL)
+ return -1;
+ return cmdsrv_serv_wait(cmdsrv_server, timeoutmsec);
+}
+
+int
+cmdsrv_handle_requests()
+{
+ cmdsrv_handle_t conn;
+ char_u *abuf;
+ size_t abufsize;
+ cmdsrv_message_T msg;
+ int n;
+
+ if (cmdsrv_server == NULL)
+ return -1;
+
+ for (;;)
+ {
+ if (got_int)
+ return -1;
+
+ n = cmdsrv_serv_wait(cmdsrv_server, 0);
+ if (n < 0)
+ return -1;
+ if (n == 0)
+ return 0;
+
+ if (cmdsrv_serv_accept(cmdsrv_server, &conn) != 0)
+ continue;
+
+ if (cmdsrv_read_message(conn, (void **)&abuf, &abufsize) != 0)
+ {
+ cmdsrv_conn_close(conn);
+ continue;
+ }
+
+ if (cmdsrv_parse_message(abuf, &msg) != 0)
+ {
+ cmdsrv_conn_close(conn);
+ continue;
+ }
+
+ if (STRICMP(msg.type, "keys") == 0)
+ {
+ cmdsrv_receive_keys(conn, &msg);
+ }
+ else if (STRICMP(msg.type, "expr") == 0)
+ {
+ cmdsrv_receive_expr(conn, &msg);
+ }
+ else if (STRICMP(msg.type, "notification") == 0)
+ {
+ cmdsrv_receive_notification(conn, &msg);
+ }
+
+ vim_free(abuf);
+
+ cmdsrv_conn_close(conn);
+ }
+}
+
+int
+cmdsrv_send_keys(char_u *serverid, char_u *keys)
+{
+ cmdsrv_handle_t conn;
+ char_u *abuf;
+ size_t abufsize;
+
+ if (serverName != NULL && STRICMP(serverid, serverName) == 0)
+ {
+ server_to_input_buf(keys);
+ return 0;
+ }
+
+ if (cmdsrv_cli_conn(serverid, &conn) != 0)
+ {
+ EMSG(_("E248: Failed to send command to the destination program"));
+ return -1;
+ }
+
+ if (cmdsrv_msg_keys(keys, &abuf, &abufsize) != 0)
+ {
+ cmdsrv_conn_close(conn);
+ return -1;
+ }
+
+ if (cmdsrv_write_message(conn, abuf, abufsize) != 0)
+ {
+ EMSG(_("E248: Failed to send command to the destination program"));
+ vim_free(abuf);
+ cmdsrv_conn_close(conn);
+ return -1;
+ }
+
+ vim_free(abuf);
+
+ if (cmdsrv_conn_close(conn) != 0)
+ {
+ EMSG(_("Exxx: close error"));
+ return -1;
+ }
+
+ return 0;
+}
+
+int
+cmdsrv_send_expr(char_u *serverid, char_u *expr, char_u **result)
+{
+ cmdsrv_handle_t conn;
+ char_u *abuf;
+ size_t abufsize;
+ cmdsrv_message_T msg;
+ char_u *reply;
+ char_u *exprbuf;
+
+ if (serverName != NULL && STRICMP(serverid, serverName) == 0)
+ {
+ /* Use allocated buffer for string literal because eval may
+ * modify expr temporarily. */
+ exprbuf = vim_strsave(expr);
+ if (exprbuf == NULL)
+ return -1;
+ reply = eval_client_expr_to_string(exprbuf);
+ vim_free(exprbuf);
+ if (result != NULL)
+ {
+ if (reply == NULL)
+ *result = vim_strsave((char_u *)_(e_invexprmsg));
+ else
+ *result = reply;
+ }
+ else
+ vim_free(reply);
+ return reply == NULL ? -1 : 0;
+ }
+
+ if (cmdsrv_cli_conn(serverid, &conn) != 0)
+ {
+ EMSG(_("E248: Failed to send command to the destination program"));
+ return -1;
+ }
+
+ if (cmdsrv_msg_expr(expr, &abuf, &abufsize) != 0)
+ {
+ cmdsrv_conn_close(conn);
+ return -1;
+ }
+
+ if (cmdsrv_write_message(conn, abuf, abufsize) != 0)
+ {
+ EMSG(_("E248: Failed to send command to the destination program"));
+ vim_free(abuf);
+ cmdsrv_conn_close(conn);
+ return -1;
+ }
+
+ vim_free(abuf);
+
+ if (cmdsrv_read_message(conn, (void **)&abuf, &abufsize) != 0)
+ {
+ EMSG(_("Exxx: Failed to receive result"));
+ cmdsrv_conn_close(conn);
+ return -1;
+ }
+
+ if (cmdsrv_parse_message(abuf, &msg) != 0
+ || STRICMP(msg.type, "reply") != 0)
+ {
+ EMSG(_("Exxx: Failed to parse result"));
+ vim_free(abuf);
+ cmdsrv_conn_close(conn);
+ return -1;
+ }
+
+ if (cmdsrv_conn_close(conn) != 0)
+ {
+ EMSG(_("Exxx: close error"));
+ vim_free(abuf);
+ return -1;
+ }
+
+ if (result != NULL)
+ *result = cmdsrv_convert(msg.encoding, msg.reply);
+
+ vim_free(abuf);
+
+ return msg.ncode == 0 ? 0 : -1;
+}
+
+int
+cmdsrv_send_notification(char_u *serverid, char_u *reply)
+{
+ cmdsrv_handle_t conn;
+ char_u *abuf;
+ size_t abufsize;
+
+ if (cmdsrv_cli_conn(serverid, &conn) != 0)
+ {
+ EMSG(_("E248: Failed to send command to the destination program"));
+ return -1;
+ }
+
+ if (cmdsrv_msg_notification(reply, &abuf, &abufsize) != 0)
+ {
+ cmdsrv_conn_close(conn);
+ return -1;
+ }
+
+ if (cmdsrv_write_message(conn, abuf, abufsize) != 0)
+ {
+ EMSG(_("E248: Failed to send command to the destination program"));
+ vim_free(abuf);
+ cmdsrv_conn_close(conn);
+ return -1;
+ }
+
+ vim_free(abuf);
+
+ if (cmdsrv_conn_close(conn) != 0)
+ {
+ EMSG(_("Exxx: close error"));
+ return -1;
+ }
+
+ return 0;
+}
+
+int
+cmdsrv_foreground(char_u *serverid)
+{
+#ifdef WIN3264
+ HWND hWnd;
+ char_u *windowidstr;
+ long windowid;
+ char_u *endp;
+
+ if (cmdsrv_send_expr(serverid, "v:windowid", &windowidstr) != 0)
+ return -1;
+
+ if (windowidstr == NULL)
+ return -1;
+
+ errno = 0;
+ windowid = strtol(windowidstr, (char **)&endp, 10);
+ if (errno != 0 || *endp != NUL || endp == windowidstr)
+ {
+ vim_free(windowidstr);
+ return -1;
+ }
+
+ if (windowid == 0)
+ return -1;
+
+ hWnd = (HWND)LongToHandle(windowid);
+
+ SetForegroundWindow(hWnd);
+
+ return 0;
+#else
+ return cmdsrv_send_expr(serverid, "foreground()", NULL);
+#endif
+}
+
+int
+cmdsrv_peek_reply(char_u *serverid, char_u **pstr)
+{
+ cmdsrv_server_reply_T *p;
+
+ p = cmdsrv_reply_find(serverid);
+ if (p != NULL && p->strings.ga_len > 0)
+ *pstr = (char_u *)p->strings.ga_data;
+ else
+ *pstr = NULL;
+
+ return 0;
+}
+
+int
+cmdsrv_read_reply(char_u *serverid, char_u **pstr)
+{
+ cmdsrv_server_reply_T *p;
+ char_u *s;
+ int len;
+
+ p = cmdsrv_reply_find(serverid);
+ if (p != NULL && p->strings.ga_len > 0)
+ {
+ *pstr = vim_strsave(p->strings.ga_data);
+ len = STRLEN(*pstr) + 1;
+ if (len < p->strings.ga_len)
+ {
+ s = (char_u *)p->strings.ga_data;
+ mch_memmove(s, s + len, p->strings.ga_len - len);
+ p->strings.ga_len -= len;
+ }
+ else
+ {
+ cmdsrv_reply_delete(serverid);
+ }
+ return 0;
+ }
+
+ return -1;
+}
+
+int
+cmdsrv_wait_reply(char_u *serverid, char_u **pstr)
+{
+ char_u *exists;
+
+ while (!got_int)
+ {
+ exists = cmdsrv_find_server(serverid, FALSE);
+ if (exists == NULL)
+ return -1;
+ vim_free(exists);
+
+ if (cmdsrv_peek_reply(serverid, pstr) != 0)
+ return -1;
+
+ if (*pstr != NULL)
+ {
+ if (cmdsrv_read_reply(serverid, pstr) != 0)
+ return -1;
+ return 0;
+ }
+
+ if (cmdsrv_wait_request(CMDSRV_SEND_MSEC_POLL) < 0)
+ return -1;
+
+ if (cmdsrv_handle_requests() != 0)
+ return -1;
+ }
+
+ return -1;
+}
+
+char_u *
+cmdsrv_find_server(char_u *name, int loose)
+{
+ char_u *list;
+ char_u *res;
+ char_u *p;
+ char_u *e;
+ size_t len;
+
+ list = cmdsrv_list(NUL);
+ if (list == NULL)
+ return NULL;
+
+ for (p = list; *p != NUL; p += STRLEN(p) + 1)
+ {
+ if (STRICMP(p, name) == 0)
+ {
+ res = vim_strsave(p);
+ vim_free(list);
+ return res;
+ }
+ }
+
+ if (!loose || cmdsrv_is_serial_name(name))
+ return NULL;
+
+ len = STRLEN(name);
+
+ for (p = list; *p != NUL; p += STRLEN(p) + 1)
+ {
+ if (STRNICMP(p, name, len) == 0)
+ {
+ e = skipdigits(p + len);
+ if (*e == NUL)
+ {
+ res = vim_strsave(p);
+ vim_free(list);
+ return res;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+/*
+ * @return percent-encoded string in allocated memory, NULL for error.
+ */
+char_u *
+cmdsrv_urlencode(char_u *str)
+{
+ char_u *buf;
+ char_u *s;
+ char_u *d;
+
+ buf = (char_u *)lalloc_clear((STRLEN(str) * 3) + 1, TRUE);
+ if (buf == NULL)
+ return NULL;
+
+ d = buf;
+ s = str;
+ while (*s != NUL)
+ {
+ if (ASCII_ISALPHA(*s) || VIM_ISDIGIT(*s)
+ || *s == '-' || *s == '.' || *s == '_' || *s == '~')
+ *d++ = *s++;
+ else
+ d += sprintf(d, "%%%02x", *s++);
+ }
+ *d = NUL;
+
+ return buf;
+}
+
+
+/*
+ * @return percent-decoded string in allocated memory, NULL for error.
+ */
+char_u *
+cmdsrv_urldecode(char_u *str)
+{
+ char_u *buf;
+ char_u *s;
+ char_u *d;
+ int c;
+
+ buf = (char_u *)lalloc_clear(STRLEN(str) + 1, TRUE);
+ if (buf == NULL)
+ return NULL;
+
+ d = buf;
+ s = str;
+ while (*s != NUL)
+ {
+ if (*s == '%')
+ {
+ c = hexhex2nr(&s[1]);
+ if (c == -1)
+ {
+ vim_free(buf);
+ return NULL;
+ }
+ *d++ = c;
+ s += 3;
+ }
+ else
+ {
+ *d++ = *s++;
+ }
+ }
+ *d = NUL;
+
+ return buf;
+}
+
+static int
+cmdsrv_is_serial_name(char_u *name)
+{
+ size_t len;
+
+ len = STRLEN(name);
+ if (len > 1 && vim_isdigit(name[len - 1]))
+ return TRUE;
+ return FALSE;
+}
+
+static cmdsrv_server_reply_T *
+cmdsrv_reply_find(char_u *serverid)
+{
+ cmdsrv_server_reply_T *p;
+ int i;
+
+ p = (cmdsrv_server_reply_T *)cmdsrv_reply.ga_data;
+ for (i = 0; i < cmdsrv_reply.ga_len; ++i)
+ {
+ if (STRICMP(p[i].serverid, serverid) == 0)
+ return &p[i];
+ }
+
+ return NULL;
+}
+
+static int
+cmdsrv_reply_add(char_u *serverid, char_u *str)
+{
+ cmdsrv_server_reply_T *p;
+
+ p = cmdsrv_reply_find(serverid);
+
+ if (p == NULL)
+ {
+ if (ga_grow(&cmdsrv_reply, 1) != OK)
+ return -1;
+ p = ((cmdsrv_server_reply_T *)cmdsrv_reply.ga_data)
+ + cmdsrv_reply.ga_len;
+ p->serverid = vim_strsave(serverid);
+ if (p->serverid == NULL)
+ return -1;
+ ga_init2(&p->strings, 1, 100);
+ cmdsrv_reply.ga_len++;
+ }
+
+ ga_concat(&p->strings, str);
+ ga_append(&p->strings, NUL);
+
+ return 0;
+}
+
+static int
+cmdsrv_reply_delete(char_u *serverid)
+{
+ cmdsrv_server_reply_T *p;
+ cmdsrv_server_reply_T *e;
+
+ p = cmdsrv_reply_find(serverid);
+
+ if (p != NULL)
+ {
+ e = ((cmdsrv_server_reply_T *)cmdsrv_reply.ga_data)
+ + cmdsrv_reply.ga_len;
+ ga_clear(&p->strings);
+ mch_memmove(p, p + 1, (e - (p + 1)) * sizeof(*p));
+ cmdsrv_reply.ga_len--;
+ }
+
+ return 0;
+}
+
+static int
+cmdsrv_msg_keys(char_u *keys, char_u **abuf, size_t *abufsize)
+{
+ garray_T ga;
+ char_u *sender;
+
+ sender = serverName;
+ if (sender == NULL)
+ sender = (char_u *)"";
+
+ ga_init2(&ga, (int)sizeof(char), 100);
+
+ ga_concat(&ga, "type");
+ ga_append(&ga, NUL);
+ ga_concat(&ga, "keys");
+ ga_append(&ga, NUL);
+
+ ga_concat(&ga, "sender");
+ ga_append(&ga, NUL);
+ ga_concat(&ga, sender);
+ ga_append(&ga, NUL);
+
+ ga_concat(&ga, "script");
+ ga_append(&ga, NUL);
+ ga_concat(&ga, keys);
+ ga_append(&ga, NUL);
+
+#ifdef FEAT_MBYTE
+ ga_concat(&ga, "encoding");
+ ga_append(&ga, NUL);
+ ga_concat(&ga, p_enc);
+ ga_append(&ga, NUL);
+#endif
+
+ ga_append(&ga, NUL);
+
+ *abuf = ga.ga_data;
+ *abufsize = ga.ga_len;
+
+ return 0;
+}
+
+static int
+cmdsrv_msg_expr(char_u *expr, char_u **abuf, size_t *abufsize)
+{
+ garray_T ga;
+ char_u *sender;
+
+ sender = serverName;
+ if (sender == NULL)
+ sender = (char_u *)"";
+
+ ga_init2(&ga, (int)sizeof(char), 100);
+
+ ga_concat(&ga, "type");
+ ga_append(&ga, NUL);
+ ga_concat(&ga, "expr");
+ ga_append(&ga, NUL);
+
+ ga_concat(&ga, "sender");
+ ga_append(&ga, NUL);
+ ga_concat(&ga, sender);
+ ga_append(&ga, NUL);
+
+ ga_concat(&ga, "script");
+ ga_append(&ga, NUL);
+ ga_concat(&ga, expr);
+ ga_append(&ga, NUL);
+
+#ifdef FEAT_MBYTE
+ ga_concat(&ga, "encoding");
+ ga_append(&ga, NUL);
+ ga_concat(&ga, p_enc);
+ ga_append(&ga, NUL);
+#endif
+
+ ga_append(&ga, NUL);
+
+ *abuf = ga.ga_data;
+ *abufsize = ga.ga_len;
+
+ return 0;
+}
+
+static int
+cmdsrv_msg_reply(char_u *reply, int code, char_u **abuf, size_t *abufsize)
+{
+ garray_T ga;
+ char_u *sender;
+ char codestr[NUMBUFLEN];
+
+ sender = serverName;
+ if (sender == NULL)
+ sender = (char_u *)"";
+
+ vim_snprintf(codestr, sizeof(codestr), "%d", code);
+
+ ga_init2(&ga, (int)sizeof(char), 100);
+
+ ga_concat(&ga, "type");
+ ga_append(&ga, NUL);
+ ga_concat(&ga, "reply");
+ ga_append(&ga, NUL);
+
+ ga_concat(&ga, "sender");
+ ga_append(&ga, NUL);
+ ga_concat(&ga, sender);
+ ga_append(&ga, NUL);
+
+ ga_concat(&ga, "reply");
+ ga_append(&ga, NUL);
+ ga_concat(&ga, reply);
+ ga_append(&ga, NUL);
+
+ ga_concat(&ga, "code");
+ ga_append(&ga, NUL);
+ ga_concat(&ga, codestr);
+ ga_append(&ga, NUL);
+
+#ifdef FEAT_MBYTE
+ ga_concat(&ga, "encoding");
+ ga_append(&ga, NUL);
+ ga_concat(&ga, p_enc);
+ ga_append(&ga, NUL);
+#endif
+
+ ga_append(&ga, NUL);
+
+ *abuf = ga.ga_data;
+ *abufsize = ga.ga_len;
+
+ return 0;
+}
+
+static int
+cmdsrv_msg_notification(char_u *reply, char_u **abuf, size_t *abufsize)
+{
+ char_u *sender;
+ garray_T ga;
+
+ sender = serverName;
+ if (sender == NULL)
+ sender = (char_u *)"";
+
+ ga_init2(&ga, (int)sizeof(char), 100);
+
+ ga_concat(&ga, "type");
+ ga_append(&ga, NUL);
+ ga_concat(&ga, "notification");
+ ga_append(&ga, NUL);
+
+ ga_concat(&ga, "sender");
+ ga_append(&ga, NUL);
+ ga_concat(&ga, sender);
+ ga_append(&ga, NUL);
+
+ ga_concat(&ga, "reply");
+ ga_append(&ga, NUL);
+ ga_concat(&ga, reply);
+ ga_append(&ga, NUL);
+
+#ifdef FEAT_MBYTE
+ ga_concat(&ga, "encoding");
+ ga_append(&ga, NUL);
+ ga_concat(&ga, p_enc);
+ ga_append(&ga, NUL);
+#endif
+
+ ga_append(&ga, NUL);
+
+ *abuf = ga.ga_data;
+ *abufsize = ga.ga_len;
+
+ return 0;
+}
+
+static int
+cmdsrv_parse_message(char_u *msg, cmdsrv_message_T *result)
+{
+ char_u *key;
+ char_u *value;
+ char_u *p;
+ char_u *endp;
+
+ vim_memset(result, 0, sizeof(*result));
+
+ p = msg;
+ while (*p != NUL)
+ {
+ key = p;
+ p += STRLEN(p) + 1;
+ value = p;
+ p += STRLEN(p) + 1;
+ if (STRICMP(key, "type") == 0)
+ result->type = value;
+ else if (STRICMP(key, "sender") == 0)
+ result->sender = value;
+ else if (STRICMP(key, "script") == 0)
+ result->script = value;
+ else if (STRICMP(key, "reply") == 0)
+ result->reply = value;
+ else if (STRICMP(key, "code") == 0)
+ result->code = value;
+ else if (STRICMP(key, "encoding") == 0)
+ result->encoding = value;
+ else
+ return -1;
+ }
+
+ if (result->code != NULL)
+ {
+ errno = 0;
+ result->ncode = strtol(result->code, (char **)&endp, 10);
+ if (errno != 0 || *endp != NUL || endp == result->code)
+ return -1;
+ }
+
+ if (result->type == NULL)
+ {
+ return -1;
+ }
+ else if (STRICMP(result->type, "keys") == 0)
+ {
+ if (result->sender == NULL || result->script == NULL)
+ return -1;
+ }
+ else if (STRICMP(result->type, "expr") == 0)
+ {
+ if (result->sender == NULL || result->script == NULL)
+ return -1;
+ }
+ else if (STRICMP(result->type, "reply") == 0)
+ {
+ if (result->sender == NULL || result->reply == NULL
+ || result->code == NULL)
+ return -1;
+ }
+ else if (STRICMP(result->type, "notification") == 0)
+ {
+ if (result->sender == NULL || result->reply == NULL)
+ return -1;
+ }
+ else
+ {
+ return -1;
+ }
+
+ return 0;
+}
+
+static int
+cmdsrv_receive_keys(cmdsrv_handle_t conn, cmdsrv_message_T *pmsg)
+{
+ char_u *script;
+
+ /* Remember in global */
+ vim_free(cmdsrv_clientid);
+ cmdsrv_clientid = vim_strsave(pmsg->sender);
+
+ script = cmdsrv_convert(pmsg->encoding, pmsg->script);
+ if (script == NULL)
+ return -1;
+
+ server_to_input_buf(script);
+
+ vim_free(script);
+
+ return 0;
+}
+
+static int
+cmdsrv_receive_expr(cmdsrv_handle_t conn, cmdsrv_message_T *pmsg)
+{
+ char_u *script;
+ char_u *result;
+ char_u *reply;
+ char_u *abuf;
+ size_t abufsize;
+ int code;
+
+ /* Remember in global */
+ vim_free(cmdsrv_clientid);
+ cmdsrv_clientid = vim_strsave(pmsg->sender);
+
+ script = cmdsrv_convert(pmsg->encoding, pmsg->script);
+ if (script == NULL)
+ return -1;
+
+ result = eval_client_expr_to_string(script);
+
+ vim_free(script);
+
+ if (result != NULL)
+ {
+ reply = result;
+ code = 0;
+ }
+ else
+ {
+ reply = (char_u *)_(e_invexprmsg);
+ code = 1;
+ }
+
+ if (cmdsrv_msg_reply(reply, code, &abuf, &abufsize) != 0)
+ {
+ vim_free(result);
+ return -1;
+ }
+
+ vim_free(result);
+
+ if (cmdsrv_write_message(conn, abuf, abufsize) != 0)
+ {
+ vim_free(abuf);
+ return -1;
+ }
+
+ vim_free(abuf);
+
+ return 0;
+}
+
+static int
+cmdsrv_receive_notification(cmdsrv_handle_t conn, cmdsrv_message_T *pmsg)
+{
+ char_u *reply;
+
+ reply = cmdsrv_convert(pmsg->encoding, pmsg->reply);
+ if (reply == NULL)
+ return -1;
+
+ if (cmdsrv_reply_add(pmsg->sender, reply) != 0)
+ {
+ vim_free(reply);
+ return -1;
+ }
+
+#ifdef FEAT_AUTOCMD
+ apply_autocmds(EVENT_REMOTEREPLY, pmsg->sender, reply, TRUE, curbuf);
+#endif
+
+ vim_free(reply);
+
+ return 0;
+}
+
+static char_u *
+cmdsrv_convert(char_u *client_enc, char_u *data)
+{
+#ifdef FEAT_MBYTE
+ if (client_enc != NULL && p_enc != NULL)
+ {
+ vimconv_T vimconv;
+ char_u *res;
+
+ 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);
+ else
+ res = vim_strsave(data);
+ convert_setup(&vimconv, NULL, NULL);
+
+ return res;
+ }
+#endif
+ return vim_strsave(data);
+}
+
+#if defined(FEAT_GUI_X11)
+static void
+cmdsrv_message_from_client(XtPointer clientData UNUSED,
+ int *unused1 UNUSED,
+ XtInputId *unused2 UNUSED)
+{
+ cmdsrv_handle_requests();
+}
+#elif defined(FEAT_GUI_GTK)
+static void
+cmdsrv_message_from_client(gpointer clientData UNUSED,
+ gint unused1 UNUSED,
+ GdkInputCondition unused2 UNUSED)
+{
+ cmdsrv_handle_requests();
+}
+#endif
+
+#endif /* FEAT_CLIENTSERVER */
diff -r 15b934a16641 -r 2082fc32d223 src/if_cmdsrv_unix.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/if_cmdsrv_unix.c Thu Sep 15 21:25:11 2011 +0900
@@ -0,0 +1,805 @@
+
+#include "vim.h"
+#include "version.h"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#ifdef HAVE_GETPEERUCRED
+# include <ucred.h>
+#endif
+
+/* for struct xucred */
+#ifdef LOCAL_PEERCRED
+# include <sys/ucred.h>
+#endif
+
+#define CMDSRV_POLL_INTERVAL 1000
+
+struct cmdsrv_server {
+ int handle;
+ char_u *path;
+};
+
+struct cmdsrv_connection {
+ int handle;
+};
+
+typedef void *cmdsrv_handle_t;
+
+static char_u *cmdsrv_dir(void);
+static char_u *cmdsrv_prefix(void);
+static char_u *cmdsrv_make_address(char_u *serverid);
+static char_u *cmdsrv_list(int sep);
+static int cmdsrv_is_alive(char_u *serverid);
+static uid_t cmdsrv_getpeeruid(int fd);
+static int cmdsrv_serv_listen(char_u *serverid, cmdsrv_handle_t *pserver);
+static int cmdsrv_serv_accept(cmdsrv_handle_t server, cmdsrv_handle_t *pconn);
+static int cmdsrv_serv_wait(cmdsrv_handle_t server, int timeoutmsec);
+static int cmdsrv_serv_close(cmdsrv_handle_t server);
+static int cmdsrv_cli_conn(char_u *serverid, cmdsrv_handle_t *pconn);
+static int cmdsrv_conn_close(cmdsrv_handle_t conn);
+static int cmdsrv_read_message(cmdsrv_handle_t conn, void **pabuf, size_t *pabufsize);
+static int cmdsrv_write_message(cmdsrv_handle_t conn, void *buf, size_t bufsize);
+static int cmdsrv_wait(int rfd, int wfd, int timeoutmsec);
+static int _ga_concatmemory(garray_T *gap, void *buf, size_t bufsize);
+static long_u _GetTickCount(void);
+
+/*
+ * @return directory path without last separator
+ */
+static char_u *
+cmdsrv_dir(void)
+{
+ static char_u buf[256];
+
+ vim_snprintf(buf, sizeof(buf), "/tmp/vim-cmdsrv-%d", (int)getuid());
+
+ return buf;
+}
+
+static char_u *
+cmdsrv_prefix(void)
+{
+ static char_u buf[256];
+
+ vim_snprintf(buf, sizeof(buf), "");
+
+ return buf;
+}
+
+static char_u *
+cmdsrv_make_address(char_u *serverid)
+{
+ garray_T ga;
+ char_u *upname;
+ char_u *encoded;
+
+ upname = strup_save(serverid);
+ if (upname == NULL)
+ return NULL;
+
+ encoded = cmdsrv_urlencode(upname);
+ if (encoded == NULL)
+ {
+ vim_free(upname);
+ return NULL;
+ }
+
+ vim_free(upname);
+
+ ga_init2(&ga, (int)sizeof(char), 100);
+
+ ga_concat(&ga, cmdsrv_dir());
+ ga_concat(&ga, "/");
+ ga_concat(&ga, cmdsrv_prefix());
+ ga_concat(&ga, encoded);
+
+ vim_free(encoded);
+
+ return (char_u *)ga.ga_data;
+}
+
+static char_u *
+cmdsrv_list(int sep)
+{
+ garray_T ga;
+ char_u buf[256];
+ char_u *pat[1];
+ int num_files;
+ char_u **files;
+ int flags = EW_FILE | EW_ICASE | EW_SILENT;
+ char_u *serverid;
+ char_u *tail;
+ char_u *path;
+ char_u *prefix;
+ int i;
+
+ prefix = cmdsrv_prefix();
+
+ vim_snprintf(buf, sizeof(buf), "%s/%s*", cmdsrv_dir(), prefix);
+
+ pat[0] = buf;
+
+ if (gen_expand_wildcards(1, pat, &num_files, &files, flags) == FAIL)
+ {
+ return vim_strsave((char_u *)"");
+ }
+
+ ga_init2(&ga, (int)sizeof(char), 100);
+
+ for (i = 0; i < num_files; ++i)
+ {
+ path = files[i];
+ tail = gettail(path);
+ if (STRNICMP(tail, prefix, STRLEN(prefix)) == 0)
+ {
+ serverid = cmdsrv_urldecode(tail + STRLEN(prefix));
+ if (serverid != NULL)
+ {
+#if 0
+ if (!cmdsrv_is_alive(serverid)
+ && (errno == ENOENT || errno == ECONNREFUSED))
+ {
+ /* server might down with trouble. */
+ mch_remove(path);
+ }
+ else
+#endif
+ {
+ ga_concat(&ga, serverid);
+ ga_append(&ga, sep);
+ }
+ vim_free(serverid);
+ }
+ }
+ }
+
+ ga_append(&ga, NUL);
+
+ FreeWild(num_files, files);
+
+ return (char_u *)ga.ga_data;
+}
+
+static int
+cmdsrv_is_alive(char_u *serverid)
+{
+ cmdsrv_handle_t conn;
+
+ if (cmdsrv_cli_conn(serverid, &conn) == 0)
+ {
+ cmdsrv_conn_close(conn);
+ return 1;
+ }
+
+ return 0;
+}
+
+/*
+ * @return peer uid. -1 for error.
+ * TODO: more variant?
+ */
+static uid_t
+cmdsrv_getpeeruid(int fd)
+{
+#if defined(HAVE_GETPEERUCRED)
+ /* Solaris */
+ {
+ ucred_t *cred = NULL;
+ uid_t uid;
+
+ if (getpeerucred(fd, &cred) != 0)
+ return -1;
+ uid = ucred_geteuid(cred);
+ ucred_free(cred);
+ return uid;
+ }
+#elif defined(HAVE_GETPEEREID)
+ /* FreeBSD */
+ {
+ uid_t uid;
+ gid_t gid;
+
+ if (getpeereid(fd, &uid, &gid) != 0)
+ return -1;
+ return uid;
+ }
+#elif defined(LOCAL_PEERCRED)
+ /* FreeBSD */
+ {
+ struct xucred cred;
+ socklen_t len;
+
+ len = sizeof(cred);
+ if (getsockopt(fd, 0, LOCAL_PEERCRED, &cred, &len) != 0)
+ return -1;
+ return cred.cr_uid;
+ }
+#elif defined(SO_PEERCRED)
+ /* Linux */
+ {
+ struct ucred cred;
+ socklen_t len;
+
+ len = sizeof(cred);
+ if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &cred, &len) != 0)
+ return -1;
+ return cred.uid;
+ }
+#else
+ {
+ /* No method available. Rely on directory permission. */
+ return getuid();
+ }
+#endif
+}
+
+static int
+cmdsrv_serv_listen(char_u *serverid, cmdsrv_handle_t *pserver)
+{
+ int fd;
+ socklen_t len;
+ struct sockaddr_un unix_addr;
+ char_u *path;
+ struct stat st;
+ struct cmdsrv_server *server;
+
+ if (!mch_isdir(cmdsrv_dir()))
+ {
+ if (vim_mkdir(cmdsrv_dir(), 0700) != 0)
+ return -1;
+ }
+
+ if (mch_stat((char *)cmdsrv_dir(), &st) != 0
+ || st.st_uid != getuid()
+ || (st.st_mode & 0777) != 0700)
+ {
+ return -1;
+ }
+
+ path = cmdsrv_make_address(serverid);
+ if (path == NULL)
+ return -1;
+
+ if (STRLEN(path) + 1 > sizeof(unix_addr.sun_path))
+ {
+ vim_free(path);
+ return -1;
+ }
+
+ fd = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (fd < 0)
+ {
+ vim_free(path);
+ return -1;
+ }
+
+ memset(&unix_addr, 0, sizeof(unix_addr));
+ unix_addr.sun_family = AF_UNIX;
+ strcpy(unix_addr.sun_path, path);
+ len = SUN_LEN(&unix_addr);
+
+ if (bind(fd, (struct sockaddr*)&unix_addr, len) != 0)
+ {
+ close(fd);
+ vim_free(path);
+ return -1;
+ }
+
+ if (listen(fd, CMDSRV_INSTANCES) != 0)
+ {
+ mch_remove(path);
+ close(fd);
+ vim_free(path);
+ return -1;
+ }
+
+ server = (struct cmdsrv_server *)lalloc_clear(
+ sizeof(struct cmdsrv_server), TRUE);
+ if (server == NULL)
+ {
+ mch_remove(path);
+ close(fd);
+ vim_free(path);
+ return -1;
+ }
+
+ server->handle = fd;
+ server->path = path;
+
+ *pserver = (cmdsrv_handle_t)server;
+
+ cmdsrv_listenfd = fd;
+#ifdef FEAT_GUI
+ cmdsrv_gui_register();
+#endif
+
+ return 0;
+}
+
+static int
+cmdsrv_serv_accept(cmdsrv_handle_t _server, cmdsrv_handle_t *pconn)
+{
+ struct cmdsrv_server *server = (struct cmdsrv_server *)_server;
+ int listenfd;
+ int fd;
+ socklen_t len;
+ struct sockaddr_un unix_addr;
+ struct cmdsrv_connection *conn;
+
+ listenfd = server->handle;
+
+ len = sizeof(unix_addr);
+ fd = accept(listenfd, (struct sockaddr *)&unix_addr, &len);
+ if (fd < 0)
+ return -1;
+
+ if (cmdsrv_getpeeruid(fd) != getuid())
+ {
+ close(fd);
+ return -1;
+ }
+
+ conn = (struct cmdsrv_connection *)lalloc_clear(
+ sizeof(struct cmdsrv_connection), TRUE);
+ if (conn == NULL)
+ {
+ close(fd);
+ return -1;
+ }
+
+ conn->handle = fd;
+
+ *pconn = (cmdsrv_handle_t)conn;
+
+ return 0;
+}
+
+static int
+cmdsrv_serv_wait(cmdsrv_handle_t _server, int timeoutmsec)
+{
+ struct cmdsrv_server *server = (struct cmdsrv_server *)_server;
+ static int lock = 0;
+ int ret;
+
+ /* Don't allow accept request while waiting request */
+ if (lock != 0)
+ return 0;
+
+ /* When watching object is signaled while polling gui event, it is
+ * never handled because waiting session is locked. Then, the
+ * signal is not reset and gui event loop never finish.
+ * Unregister watching object temporarily. */
+#ifdef FEAT_GUI
+ if (timeoutmsec != 0)
+ cmdsrv_gui_unregister();
+#endif
+
+ ++lock;
+
+ ret = cmdsrv_wait(server->handle, -1, timeoutmsec);
+
+ --lock;
+
+#ifdef FEAT_GUI
+ if (timeoutmsec != 0)
+ cmdsrv_gui_register();
+#endif
+
+ return ret;
+}
+
+static int
+cmdsrv_serv_close(cmdsrv_handle_t _server)
+{
+ struct cmdsrv_server *server = (struct cmdsrv_server *)_server;
+
+#ifdef FEAT_GUI
+ cmdsrv_gui_unregister();
+#endif
+ cmdsrv_listenfd = -1;
+
+ if (close(server->handle) != 0)
+ return -1;
+
+ mch_remove(server->path);
+
+ vim_free(server->path);
+ vim_free(server);
+
+ return 0;
+}
+
+static int
+cmdsrv_cli_conn(char_u *serverid, cmdsrv_handle_t *pconn)
+{
+ int fd;
+ socklen_t len;
+ struct sockaddr_un unix_addr;
+ int flag;
+ char_u *path;
+ struct cmdsrv_connection *conn;
+ socklen_t errlen;
+ int err;
+ int ret;
+
+ path = cmdsrv_make_address(serverid);
+ if (path == NULL)
+ return -1;
+
+ if (STRLEN(path) + 1 > sizeof(unix_addr.sun_path))
+ {
+ vim_free(path);
+ return -1;
+ }
+
+ fd = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (fd < 0)
+ {
+ vim_free(path);
+ return -1;
+ }
+
+ /* Set NONBLOCK mode to prevent to block with connect(). */
+ flag = fcntl(fd, F_GETFL, 0);
+ if (flag == -1)
+ {
+ close(fd);
+ vim_free(path);
+ return -1;
+ }
+
+ if (fcntl(fd, F_SETFL, flag | O_NONBLOCK) == -1)
+ {
+ close(fd);
+ vim_free(path);
+ return -1;
+ }
+
+ memset(&unix_addr, 0, sizeof(unix_addr));
+ unix_addr.sun_family = AF_UNIX;
+ strcpy(unix_addr.sun_path, path);
+ len = SUN_LEN(&unix_addr);
+
+ ret = connect(fd, (struct sockaddr *)&unix_addr, len);
+ if (ret < 0)
+ {
+ if (errno == EINPROGRESS)
+ {
+ if (cmdsrv_wait(-1, fd, -1) > 0)
+ {
+ errlen = sizeof(err);
+ if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &err, &errlen) == 0
+ && err == 0)
+ ret = 0;
+ }
+ }
+ }
+ if (ret < 0)
+ {
+ close(fd);
+ vim_free(path);
+ return -1;
+ }
+
+ conn = (struct cmdsrv_connection *)lalloc_clear(
+ sizeof(struct cmdsrv_connection), TRUE);
+ if (conn == NULL)
+ {
+ close(fd);
+ vim_free(path);
+ return -1;
+ }
+
+ conn->handle = fd;
+
+ *pconn = (cmdsrv_handle_t)conn;
+
+ return 0;
+}
+
+static int
+cmdsrv_conn_close(cmdsrv_handle_t _conn)
+{
+ struct cmdsrv_connection *conn = (struct cmdsrv_connection *)_conn;
+
+ if (close(conn->handle) != 0)
+ return -1;
+
+ vim_free(conn);
+
+ return 0;
+}
+
+static int
+cmdsrv_read_message(cmdsrv_handle_t _conn, void **pabuf, size_t *pabufsize)
+{
+ struct cmdsrv_connection *conn = (struct cmdsrv_connection *)_conn;
+ int fd;
+ char buf[BUFSIZ];
+ ssize_t nread;
+ garray_T ga;
+
+ fd = conn->handle;
+
+ ga_init2(&ga, (int)sizeof(char), 100);
+
+ for (;;)
+ {
+ if (cmdsrv_wait(fd, -1, -1) <= 0)
+ {
+ ga_clear(&ga);
+ return -1;
+ }
+
+ nread = read(fd, buf, sizeof(buf));
+ if (nread < 0)
+ {
+ if (errno == EINTR)
+ continue;
+ ga_clear(&ga);
+ return -1;
+ }
+ else if (nread == 0)
+ break;
+ if (_ga_concatmemory(&ga, buf, nread) != OK)
+ {
+ ga_clear(&ga);
+ return -1;
+ }
+ }
+
+ /* On MacOSX, shutdown() may fail when the connection is already
+ * closed by peer. */
+ if (shutdown(fd, SHUT_RD) < 0 && errno != ENOTCONN)
+ {
+ ga_clear(&ga);
+ return -1;
+ }
+
+ *pabufsize = ga.ga_len;
+
+ /* ensure NUL terminated to ease to parse */
+ ga_append(&ga, NUL);
+ ga_append(&ga, NUL);
+ ga_append(&ga, NUL);
+
+ *pabuf = ga.ga_data;
+
+ return 0;
+}
+
+static int
+cmdsrv_write_message(cmdsrv_handle_t _conn, void *buf, size_t bufsize)
+{
+ struct cmdsrv_connection *conn = (struct cmdsrv_connection *)_conn;
+ int fd;
+ ssize_t nwrite;
+ size_t nwritten;
+
+ fd = conn->handle;
+
+ nwritten = 0;
+
+ while (nwritten < bufsize)
+ {
+ if (cmdsrv_wait(-1, fd, -1) <= 0)
+ {
+ return -1;
+ }
+
+ nwrite = write(fd, ((char*)buf) + nwritten, bufsize - nwritten);
+ if (nwrite < 0)
+ {
+ if (errno == EINTR)
+ continue;
+ return -1;
+ }
+ nwritten += nwrite;
+ }
+
+ /* On MacOSX, shutdown() may fail when the connection is already
+ * closed by peer. */
+ if (shutdown(fd, SHUT_WR) < 0 && errno != ENOTCONN)
+ return -1;
+
+ return 0;
+}
+
+/*
+ * Wait single object, rfd for read, wfd for write.
+ * @param timeoutmsec -1 infinit, 0 nowait, >0 millisecond
+ * @return -1 error, 0 timeout, 1 received (not handled yet)
+ */
+#ifdef HAVE_SELECT
+static int
+cmdsrv_wait(int rfd, int wfd, int timeoutmsec)
+{
+ int maxfd;
+ struct timeval tv;
+ fd_set rset;
+ fd_set wset;
+ int n;
+ long_u starttime;
+ long_u lefttime;
+ long_u waittime;
+
+ starttime = _GetTickCount();
+
+ while (!got_int)
+ {
+ maxfd = 0;
+
+ FD_ZERO(&rset);
+ FD_ZERO(&wset);
+
+ if (rfd != -1)
+ {
+ FD_SET(rfd, &rset);
+ if (maxfd < rfd)
+ maxfd = rfd;
+ }
+
+ if (wfd != -1)
+ {
+ FD_SET(wfd, &wset);
+ if (maxfd < wfd)
+ maxfd = wfd;
+ }
+
+ if (cmdsrv_listenfd != -1
+ && cmdsrv_listenfd != rfd && cmdsrv_listenfd != wfd)
+ {
+ FD_SET(cmdsrv_listenfd, &rset);
+ if (maxfd < cmdsrv_listenfd)
+ maxfd = cmdsrv_listenfd;
+ }
+
+ lefttime = _GetTickCount() - starttime;
+ if (timeoutmsec < 0)
+ waittime = CMDSRV_POLL_INTERVAL;
+ else if (timeoutmsec == 0)
+ waittime = 0;
+ else if ((long_u)timeoutmsec <= lefttime)
+ waittime = 0;
+ else if ((long_u)timeoutmsec - lefttime > CMDSRV_POLL_INTERVAL)
+ waittime = CMDSRV_POLL_INTERVAL;
+ else
+ waittime = (long_u)timeoutmsec - lefttime;
+
+ tv.tv_sec = waittime / 1000;
+ tv.tv_usec = waittime % 1000 * 1000;
+
+ n = select(maxfd + 1, &rset, &wset, NULL, &tv);
+ if (n < 0)
+ return -1;
+
+ if (rfd != -1 && FD_ISSET(rfd, &rset))
+ return 1;
+
+ if (wfd != -1 && FD_ISSET(wfd, &wset))
+ return 1;
+
+ lefttime = _GetTickCount() - starttime;
+ if (timeoutmsec == 0)
+ return 0;
+ else if (timeoutmsec > 0 && (long_u)timeoutmsec <= lefttime)
+ return 0;
+
+ cmdsrv_handle_requests();
+
+ ui_breakcheck();
+ }
+
+ return -1;
+}
+#else
+static int
+cmdsrv_wait(int rfd, int wfd, int timeoutmsec)
+{
+ struct pollfd fds[2];
+ int nfds;
+ int n;
+ long_u starttime;
+ long_u lefttime;
+ long_u waittime;
+
+ starttime = _GetTickCount();
+
+ while (!got_int)
+ {
+ nfds = 0;
+
+ if (rfd != -1)
+ {
+ fds[0].fd = rfd;
+ fds[0].events = POLLIN;
+ nfds = 1;
+ }
+
+ if (wfd != -1)
+ {
+ fds[0].fd = wfd;
+ fds[0].events = POLLOUT;
+ nfds = 1;
+ }
+
+ if (cmdsrv_listenfd != -1
+ && cmdsrv_listenfd != rfd && cmdsrv_listenfd != wfd)
+ {
+ fds[nfds].fd = cmdsrv_listenfd;
+ fds[nfds].events = POLLIN;
+ nfds++;
+ }
+
+ lefttime = _GetTickCount() - starttime;
+
+ if (timeoutmsec < 0)
+ waittime = CMDSRV_POLL_INTERVAL;
+ else if (timeoutmsec == 0)
+ waittime = 0;
+ else if ((long_u)timeoutmsec <= lefttime)
+ waittime = 0;
+ else if ((long_u)timeoutmsec - lefttime > CMDSRV_POLL_INTERVAL)
+ waittime = CMDSRV_POLL_INTERVAL;
+ else
+ waittime = (long_u)timeoutmsec - lefttime;
+
+ n = poll(fds, nfds, (int)waittime);
+ if (n < 0)
+ return -1;
+
+ if (rfd != -1)
+ {
+ if (fds[0].revents & POLLIN)
+ return 1;
+ else if (fds[0].revents & (POLLERR | POLLHUP))
+ return -1;
+ }
+
+ if (wfd != -1)
+ {
+ if (fds[0].revents & POLLOUT)
+ return 1;
+ else if (fds[0].revents & (POLLERR | POLLHUP))
+ return -1;
+ }
+
+ lefttime = _GetTickCount() - starttime;
+ if (timeoutmsec == 0)
+ return 0;
+ else if (timeoutmsec > 0 && (long_u)timeoutmsec <= lefttime)
+ return 0;
+
+ cmdsrv_handle_requests();
+
+ ui_breakcheck();
+ }
+
+ return -1;
+}
+#endif
+
+static int
+_ga_concatmemory(garray_T *gap, void *buf, size_t bufsize)
+{
+ if (ga_grow(gap, bufsize) != OK)
+ return FAIL;
+ mch_memmove(((char *)gap->ga_data) + gap->ga_len, buf, bufsize);
+ gap->ga_len += bufsize;
+ return OK;
+}
+
+static long_u
+_GetTickCount(void)
+{
+ struct timeval tv;
+
+ if (gettimeofday(&tv, NULL) != 0)
+ return (long_u)-1;
+
+ return (tv.tv_sec * 1000) + (tv.tv_usec / 1000);
+}
+
diff -r 15b934a16641 -r 2082fc32d223 src/if_cmdsrv_win32.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/if_cmdsrv_win32.c Thu Sep 15 21:25:11 2011 +0900
@@ -0,0 +1,639 @@
+
+#include "vim.h"
+#include "version.h"
+
+#include <stddef.h>
+
+#define CMDSRV_POLL_INTERVAL 1000
+
+typedef struct {
+ OVERLAPPED oOverlap;
+ HANDLE hPipeInst;
+ BOOL iopending;
+} PIPEINST, *LPPIPEINST;
+
+struct cmdsrv_server {
+ PIPEINST pipes[CMDSRV_INSTANCES];
+ HANDLE hEvents[CMDSRV_INSTANCES];
+};
+
+struct cmdsrv_connection {
+ PIPEINST Pipe;
+ LPPIPEINST Server;
+};
+
+typedef void *cmdsrv_handle_t;
+
+static char_u *cmdsrv_dir(void);
+static char_u *cmdsrv_prefix(void);
+static char_u *cmdsrv_make_address(char_u *serverid);
+static char_u *cmdsrv_list(int sep);
+static int cmdsrv_serv_listen(char_u *serverid, cmdsrv_handle_t *pserver);
+static int cmdsrv_serv_accept(cmdsrv_handle_t server, cmdsrv_handle_t *pconn);
+static int cmdsrv_serv_wait(cmdsrv_handle_t server, int timeoutmsec);
+static int cmdsrv_serv_close(cmdsrv_handle_t server);
+static int cmdsrv_cli_conn(char_u *serverid, cmdsrv_handle_t *pconn);
+static int cmdsrv_conn_close(cmdsrv_handle_t conn);
+static int cmdsrv_read_message(cmdsrv_handle_t conn, void **pabuf, size_t *pabufsize);
+static int cmdsrv_write_message(cmdsrv_handle_t conn, void *buf, size_t bufsize);
+static int cmdsrv_wait(int nitems, HANDLE *objects, int *pidx, int timeoutmsec);
+static int _ga_concatmemory(garray_T *gap, void *buf, size_t bufsize);
+static BOOL DisconnectAndReconnect(LPPIPEINST lpPipe);
+static BOOL ConnectToNewClient(LPPIPEINST lpPipe);
+
+/*
+ * @return directory path without last separator
+ */
+static char_u *
+cmdsrv_dir(void)
+{
+ static char_u buf[256];
+
+ vim_snprintf(buf, sizeof(buf), "\\\\.\\pipe");
+
+ return buf;
+}
+
+static char_u *
+cmdsrv_prefix(void)
+{
+ static char_u buf[256];
+
+ vim_snprintf(buf, sizeof(buf), "vim-cmdsrv-");
+
+ return buf;
+}
+
+static char_u *
+cmdsrv_make_address(char_u *serverid)
+{
+ garray_T ga;
+ char_u *upname;
+ char_u *encoded;
+
+ upname = strup_save(serverid);
+ if (upname == NULL)
+ return NULL;
+
+ encoded = cmdsrv_urlencode(upname);
+ if (encoded == NULL)
+ {
+ vim_free(upname);
+ return NULL;
+ }
+
+ vim_free(upname);
+
+ ga_init2(&ga, (int)sizeof(char), 100);
+
+ ga_concat(&ga, cmdsrv_dir());
+ ga_concat(&ga, "\\");
+ ga_concat(&ga, cmdsrv_prefix());
+ ga_concat(&ga, encoded);
+
+ vim_free(encoded);
+
+ return (char_u *)ga.ga_data;
+}
+
+static char_u *
+cmdsrv_list(int sep)
+{
+ garray_T ga;
+ char_u buf[256];
+ char_u *serverid;
+ char_u *tail;
+ char_u *prefix;
+ WIN32_FIND_DATA finddata;
+ HANDLE h;
+
+ prefix = cmdsrv_prefix();
+
+ vim_snprintf(buf, sizeof(buf), "%s\\*", cmdsrv_dir());
+
+ ga_init2(&ga, (int)sizeof(char), 100);
+
+ h = FindFirstFile(buf, &finddata);
+ if (h == INVALID_HANDLE_VALUE)
+ {
+ ga_clear(&ga);
+ return NULL;
+ }
+
+ do
+ {
+ tail = gettail((char_u *)finddata.cFileName);
+ if (STRNICMP(tail, prefix, STRLEN(prefix)) == 0)
+ {
+ serverid = cmdsrv_urldecode(tail + STRLEN(prefix));
+ if (serverid != NULL)
+ {
+ ga_concat(&ga, serverid);
+ ga_append(&ga, sep);
+ vim_free(serverid);
+ }
+ }
+ } while (FindNextFile(h, &finddata));
+
+ ga_append(&ga, NUL);
+
+ FindClose(h);
+
+ return (char_u *)ga.ga_data;
+}
+
+static int
+cmdsrv_serv_listen(char_u *serverid, cmdsrv_handle_t *pserver)
+{
+ char_u *path;
+ int i;
+ struct cmdsrv_server *server;
+
+ path = cmdsrv_make_address(serverid);
+ if (path == NULL)
+ return -1;
+
+ server = (struct cmdsrv_server *)lalloc_clear(
+ sizeof(struct cmdsrv_server), TRUE);
+ if (server == NULL)
+ {
+ vim_free(path);
+ return -1;
+ }
+
+ for (i = 0; i < CMDSRV_INSTANCES; ++i)
+ {
+ server->pipes[i].iopending = FALSE;
+ server->pipes[i].oOverlap.hEvent = NULL;
+ server->pipes[i].hPipeInst = INVALID_HANDLE_VALUE;
+ }
+
+ for (i = 0; i < CMDSRV_INSTANCES; ++i)
+ {
+ server->pipes[i].oOverlap.hEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
+ if (server->pipes[i].oOverlap.hEvent == NULL)
+ break;
+
+ server->hEvents[i] = server->pipes[i].oOverlap.hEvent;
+
+ server->pipes[i].hPipeInst = CreateNamedPipe(
+ path,
+ PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
+ PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
+ CMDSRV_INSTANCES,
+ 0,
+ 0,
+ 0,
+ NULL);
+ if (server->pipes[i].hPipeInst == INVALID_HANDLE_VALUE)
+ break;
+
+ if (!ConnectToNewClient(&server->pipes[i]))
+ break;
+ }
+
+ if (i < CMDSRV_INSTANCES)
+ {
+ cmdsrv_serv_close(server);
+ vim_free(path);
+ return -1;
+ }
+
+ vim_free(path);
+
+ *pserver = (cmdsrv_handle_t)server;
+
+ cmdsrv_events = server->hEvents;
+
+ return 0;
+}
+
+static int
+cmdsrv_serv_accept(cmdsrv_handle_t _server, cmdsrv_handle_t *pconn)
+{
+ struct cmdsrv_server *server = (struct cmdsrv_server *)_server;
+ int idx;
+ struct cmdsrv_connection *conn;
+
+ if (cmdsrv_wait(CMDSRV_INSTANCES, server->hEvents, &idx, -1) <= 0)
+ return -1;
+
+ server->pipes[idx].iopending = FALSE;
+
+ /* Event object will be re-checked while processing connection.
+ * Turn off to prevent to be misinterpreted as new request came. */
+ if (!ResetEvent(server->hEvents[idx]))
+ {
+ DisconnectAndReconnect(&server->pipes[idx]);
+ return -1;
+ }
+
+ conn = (struct cmdsrv_connection *)lalloc_clear(
+ sizeof(struct cmdsrv_connection), TRUE);
+ if (conn == NULL)
+ {
+ DisconnectAndReconnect(&server->pipes[idx]);
+ return -1;
+ }
+
+ conn->Pipe.oOverlap.hEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
+ if (conn->Pipe.oOverlap.hEvent == NULL)
+ {
+ vim_free(conn);
+ DisconnectAndReconnect(&server->pipes[idx]);
+ return -1;
+ }
+
+ conn->Pipe.hPipeInst = server->pipes[idx].hPipeInst;
+ conn->Server = &server->pipes[idx];
+
+ *pconn = (cmdsrv_handle_t)conn;
+
+ return 0;
+}
+
+static int
+cmdsrv_serv_wait(cmdsrv_handle_t _server, int timeoutmsec)
+{
+ struct cmdsrv_server *server = (struct cmdsrv_server *)_server;
+ static int lock = 0;
+ int ret;
+
+ /* Don't allow accept request while waiting request */
+ if (lock != 0)
+ return 0;
+
+ /* When watching object is signaled while polling gui event, it is
+ * never handled because waiting session is locked. Then, the
+ * signal is not reset and gui event loop never finish.
+ * Unregister watching object temporarily. */
+#ifdef FEAT_GUI
+ if (timeoutmsec != 0)
+ cmdsrv_gui_unregister();
+#endif
+
+ ++lock;
+
+ ret = cmdsrv_wait(CMDSRV_INSTANCES, server->hEvents, NULL, timeoutmsec);
+
+ --lock;
+
+#ifdef FEAT_GUI
+ if (timeoutmsec != 0)
+ cmdsrv_gui_register();
+#endif
+
+ return ret;
+}
+
+static int
+cmdsrv_serv_close(cmdsrv_handle_t _server)
+{
+ struct cmdsrv_server *server = (struct cmdsrv_server *)_server;
+ int i;
+
+ cmdsrv_events = NULL;
+
+ for (i = 0; i < CMDSRV_INSTANCES; ++i)
+ {
+ if (server->pipes[i].iopending)
+ {
+ if (CancelIo(server->pipes[i].hPipeInst))
+ WaitForSingleObject(server->pipes[i].oOverlap.hEvent, INFINITE);
+ }
+ if (server->pipes[i].hPipeInst != INVALID_HANDLE_VALUE)
+ {
+ DisconnectNamedPipe(server->pipes[i].hPipeInst);
+ CloseHandle(server->pipes[i].hPipeInst);
+ }
+ if (server->pipes[i].oOverlap.hEvent != NULL)
+ CloseHandle(server->pipes[i].oOverlap.hEvent);
+ }
+
+ vim_free(server);
+
+ return 0;
+}
+
+static int
+cmdsrv_cli_conn(char_u *serverid, cmdsrv_handle_t *pconn)
+{
+ char_u *path;
+ struct cmdsrv_connection *conn;
+
+ path = cmdsrv_make_address(serverid);
+ if (path == NULL)
+ return -1;
+
+ conn = (struct cmdsrv_connection *)lalloc_clear(
+ sizeof(struct cmdsrv_connection), TRUE);
+ if (conn == NULL)
+ {
+ vim_free(path);
+ return -1;
+ }
+
+ conn->Pipe.oOverlap.hEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
+ if (conn->Pipe.oOverlap.hEvent == NULL)
+ {
+ vim_free(conn);
+ vim_free(path);
+ return -1;
+ }
+
+ conn->Pipe.hPipeInst = CreateFile(
+ path,
+ GENERIC_READ | GENERIC_WRITE,
+ 0,
+ NULL,
+ OPEN_EXISTING,
+ FILE_FLAG_OVERLAPPED,
+ NULL);
+ if (conn->Pipe.hPipeInst == INVALID_HANDLE_VALUE)
+ {
+ CloseHandle(conn->Pipe.oOverlap.hEvent);
+ vim_free(conn);
+ vim_free(path);
+ return -1;
+ }
+
+ conn->Server = NULL;
+
+ *pconn = (cmdsrv_handle_t)conn;
+
+ return 0;
+}
+
+static int
+cmdsrv_conn_close(cmdsrv_handle_t _conn)
+{
+ struct cmdsrv_connection *conn = (struct cmdsrv_connection *)_conn;
+
+ if (conn->Server != NULL)
+ {
+ CloseHandle(conn->Pipe.oOverlap.hEvent);
+ DisconnectAndReconnect(conn->Server);
+ }
+ else
+ {
+ CloseHandle(conn->Pipe.oOverlap.hEvent);
+ CloseHandle(conn->Pipe.hPipeInst);
+ }
+
+ vim_free(conn);
+
+ return 0;
+}
+
+static int
+cmdsrv_read_message(cmdsrv_handle_t _conn, void **pabuf, size_t *pabufsize)
+{
+ struct cmdsrv_connection *conn = (struct cmdsrv_connection *)_conn;
+ char buf[BUFSIZ];
+ DWORD nread;
+ garray_T ga;
+
+ ga_init2(&ga, (int)sizeof(char), 100);
+
+ for (;;)
+ {
+ if (ReadFile(conn->Pipe.hPipeInst, buf, sizeof(buf), &nread,
+ &conn->Pipe.oOverlap))
+ {
+ if (_ga_concatmemory(&ga, buf, nread) != OK)
+ {
+ ga_clear(&ga);
+ return -1;
+ }
+ break;
+ }
+ else if (GetLastError() == ERROR_MORE_DATA)
+ {
+ if (_ga_concatmemory(&ga, buf, nread) != OK)
+ {
+ ga_clear(&ga);
+ return -1;
+ }
+ continue;
+ }
+ else if (GetLastError() == ERROR_IO_PENDING)
+ {
+ if (cmdsrv_wait(1, &conn->Pipe.oOverlap.hEvent, NULL, -1) <= 0)
+ {
+ if (CancelIo(conn->Pipe.hPipeInst))
+ WaitForSingleObject(conn->Pipe.oOverlap.hEvent, INFINITE);
+ ga_clear(&ga);
+ return -1;
+ }
+ if (GetOverlappedResult(conn->Pipe.hPipeInst,
+ &conn->Pipe.oOverlap, &nread, FALSE))
+ {
+ if (_ga_concatmemory(&ga, buf, nread) != OK)
+ {
+ ga_clear(&ga);
+ return -1;
+ }
+ break;
+ }
+ else if (GetLastError() == ERROR_MORE_DATA)
+ {
+ if (_ga_concatmemory(&ga, buf, nread) != OK)
+ {
+ ga_clear(&ga);
+ return -1;
+ }
+ continue;
+ }
+ else
+ {
+ ga_clear(&ga);
+ return -1;
+ }
+ }
+ else
+ {
+ ga_clear(&ga);
+ return -1;
+ }
+ }
+
+ *pabufsize = ga.ga_len;
+
+ /* ensure NUL terminated to ease to parse */
+ ga_append(&ga, NUL);
+ ga_append(&ga, NUL);
+ ga_append(&ga, NUL);
+
+ *pabuf = ga.ga_data;
+
+ return 0;
+}
+
+static int
+cmdsrv_write_message(cmdsrv_handle_t _conn, void *buf, size_t bufsize)
+{
+ struct cmdsrv_connection *conn = (struct cmdsrv_connection *)_conn;
+ DWORD nwrite;
+
+ /* message pipe is atomic for each WriteFile() call. */
+ if (WriteFile(conn->Pipe.hPipeInst, buf, bufsize, &nwrite,
+ &conn->Pipe.oOverlap))
+ {
+ return 0;
+ }
+ else if (GetLastError() == ERROR_IO_PENDING)
+ {
+ if (cmdsrv_wait(1, &conn->Pipe.oOverlap.hEvent, NULL, -1) <= 0)
+ {
+ if (CancelIo(conn->Pipe.hPipeInst))
+ WaitForSingleObject(conn->Pipe.oOverlap.hEvent, INFINITE);
+ return -1;
+ }
+ if (GetOverlappedResult(conn->Pipe.hPipeInst,
+ &conn->Pipe.oOverlap, &nwrite, FALSE))
+ {
+ return 0;
+ }
+ else
+ {
+ return -1;
+ }
+ }
+ else
+ {
+ return -1;
+ }
+}
+
+/*
+ * @param timeoutmsec -1 infinit, 0 nowait, >0 millisecond
+ * @return -1 error, 0 timeout, 1 received (not handled yet)
+ */
+static int
+cmdsrv_wait(int nitems, HANDLE *objects, int *pidx, int timeoutmsec)
+{
+ HANDLE wait_objects[1 + CMDSRV_INSTANCES];
+ int wait_nitems = 0;
+ DWORD dwWait;
+ DWORD starttime;
+ DWORD lefttime;
+ DWORD waittime;
+
+ /* assert nitems == 1 || objects == cmdsrv_events */
+
+ while (wait_nitems < nitems)
+ {
+ wait_objects[wait_nitems] = objects[wait_nitems];
+ wait_nitems++;
+ }
+
+ if (objects != cmdsrv_events)
+ {
+ mch_memmove(wait_objects + wait_nitems, cmdsrv_events,
+ sizeof(HANDLE) * CMDSRV_INSTANCES);
+ wait_nitems += CMDSRV_INSTANCES;
+ }
+
+ starttime = GetTickCount();
+
+ while (!got_int)
+ {
+ lefttime = GetTickCount() - starttime;
+
+ if (timeoutmsec < 0)
+ waittime = CMDSRV_POLL_INTERVAL;
+ else if (timeoutmsec == 0)
+ waittime = 0;
+ else if ((DWORD)timeoutmsec <= lefttime)
+ waittime = 0;
+ else if ((DWORD)timeoutmsec - lefttime > CMDSRV_POLL_INTERVAL)
+ waittime = CMDSRV_POLL_INTERVAL;
+ else
+ waittime = (DWORD)timeoutmsec - lefttime;
+
+ dwWait = WaitForMultipleObjects(wait_nitems, wait_objects, FALSE,
+ waittime);
+ if (dwWait == WAIT_FAILED)
+ {
+ return -1;
+ }
+ else if (dwWait == WAIT_TIMEOUT)
+ {
+ /* continue */
+ }
+ else if (WAIT_OBJECT_0 <= dwWait && dwWait < WAIT_OBJECT_0 + nitems)
+ {
+ if (pidx != NULL)
+ *pidx = dwWait - WAIT_OBJECT_0;
+ return 1;
+ }
+ else if (WAIT_OBJECT_0 + nitems <= dwWait
+ && dwWait < WAIT_OBJECT_0 + wait_nitems)
+ {
+ /* request received */
+ }
+ else
+ {
+ return -1;
+ }
+
+ lefttime = GetTickCount() - starttime;
+ if (timeoutmsec == 0)
+ return 0;
+ else if (timeoutmsec > 0 && (DWORD)timeoutmsec <= lefttime)
+ return 0;
+
+ cmdsrv_handle_requests();
+
+ ui_breakcheck();
+ }
+
+ return -1;
+}
+
+static int
+_ga_concatmemory(garray_T *gap, void *buf, size_t bufsize)
+{
+ if (ga_grow(gap, bufsize) != OK)
+ return FAIL;
+ mch_memmove(((char *)gap->ga_data) + gap->ga_len, buf, bufsize);
+ gap->ga_len += bufsize;
+ return OK;
+}
+
+static BOOL
+DisconnectAndReconnect(LPPIPEINST lpPipe)
+{
+ if (!DisconnectNamedPipe(lpPipe->hPipeInst))
+ return FALSE;
+ return ConnectToNewClient(lpPipe);
+}
+
+static BOOL
+ConnectToNewClient(LPPIPEINST lpPipe)
+{
+ BOOL fConnected;
+
+ lpPipe->iopending = FALSE;
+
+ fConnected = ConnectNamedPipe(lpPipe->hPipeInst, &lpPipe->oOverlap);
+ /* Overlapped ConnectNamedPipe should return zero. */
+ if (fConnected)
+ {
+ return FALSE;
+ }
+
+ switch (GetLastError())
+ {
+ case ERROR_IO_PENDING:
+ lpPipe->iopending = TRUE;
+ return TRUE;
+ case ERROR_PIPE_CONNECTED:
+ if (SetEvent(lpPipe->oOverlap.hEvent))
+ return TRUE;
+ /* FALLTHROUGH */
+ default:
+ return FALSE;
+ }
+}
+
diff -r 15b934a16641 -r 2082fc32d223 src/if_xcmdsrv.c
--- a/src/if_xcmdsrv.c Wed Sep 14 19:04:40 2011 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,1498 +0,0 @@
-/* vi:set ts=8 sts=4 sw=4:
- *
- * VIM - Vi IMproved by Bram Moolenaar
- * X command server by Flemming Madsen
- *
- * 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.
- *
- * if_xcmdsrv.c: Functions for passing commands through an X11 display.
- *
- */
-
-#include "vim.h"
-#include "version.h"
-
-#if defined(FEAT_CLIENTSERVER) || defined(PROTO)
-
-# ifdef FEAT_X11
-# include <X11/Intrinsic.h>
-# include <X11/Xatom.h>
-# endif
-
-/*
- * This file provides procedures that implement the command server
- * functionality of Vim when in contact with an X11 server.
- *
- * Adapted from TCL/TK's send command in tkSend.c of the tk 3.6 distribution.
- * Adapted for use in Vim by Flemming Madsen. Protocol changed to that of tk 4
- */
-
-/*
- * Copyright (c) 1989-1993 The Regents of the University of California.
- * All rights reserved.
- *
- * Permission is hereby granted, without written agreement and without
- * license or royalty fees, to use, copy, modify, and distribute this
- * software and its documentation for any purpose, provided that the
- * above copyright notice and the following two paragraphs appear in
- * all copies of this software.
- *
- * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
- * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
- * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
- * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
- * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
- * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
- * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
- * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
- */
-
-
-/*
- * When a result is being awaited from a sent command, one of
- * the following structures is present on a list of all outstanding
- * sent commands. The information in the structure is used to
- * process the result when it arrives. You're probably wondering
- * how there could ever be multiple outstanding sent commands.
- * This could happen if Vim instances invoke each other recursively.
- * It's unlikely, but possible.
- */
-
-typedef struct PendingCommand
-{
- int serial; /* Serial number expected in result. */
- int code; /* Result Code. 0 is OK */
- char_u *result; /* String result for command (malloc'ed).
- * NULL means command still pending. */
- struct PendingCommand *nextPtr;
- /* Next in list of all outstanding commands.
- * NULL means end of list. */
-} PendingCommand;
-
-static PendingCommand *pendingCommands = NULL;
- /* List of all commands currently
- * being waited for. */
-
-/*
- * The information below is used for communication between processes
- * during "send" commands. Each process keeps a private window, never
- * even mapped, with one property, "Comm". When a command is sent to
- * an interpreter, the command is appended to the comm property of the
- * communication window associated with the interp's process. Similarly,
- * when a result is returned from a sent command, it is also appended
- * to the comm property.
- *
- * Each command and each result takes the form of ASCII text. For a
- * command, the text consists of a nul character followed by several
- * nul-terminated ASCII strings. The first string consists of a
- * single letter:
- * "c" for an expression
- * "k" for keystrokes
- * "r" for reply
- * "n" for notification.
- * Subsequent strings have the form "option value" where the following options
- * are supported:
- *
- * -r commWindow serial
- *
- * This option means that a response should be sent to the window
- * whose X identifier is "commWindow" (in hex), and the response should
- * be identified with the serial number given by "serial" (in decimal).
- * If this option isn't specified then the send is asynchronous and
- * no response is sent.
- *
- * -n name
- * "Name" gives the name of the application for which the command is
- * intended. This option must be present.
- *
- * -E encoding
- * Encoding name used for the text. This is the 'encoding' of the
- * sender. The receiver may want to do conversion to his 'encoding'.
- *
- * -s script
- * "Script" is the script to be executed. This option must be
- * present. Taken as a series of keystrokes in a "k" command where
- * <Key>'s are expanded
- *
- * The options may appear in any order. The -n and -s options must be
- * present, but -r may be omitted for asynchronous RPCs. For compatibility
- * with future releases that may add new features, there may be additional
- * options present; as long as they start with a "-" character, they will
- * be ignored.
- *
- * A result also consists of a zero character followed by several null-
- * terminated ASCII strings. The first string consists of the single
- * letter "r". Subsequent strings have the form "option value" where
- * the following options are supported:
- *
- * -s serial
- * Identifies the command for which this is the result. It is the
- * same as the "serial" field from the -s option in the command. This
- * option must be present.
- *
- * -r result
- * "Result" is the result string for the script, which may be either
- * a result or an error message. If this field is omitted then it
- * defaults to an empty string.
- *
- * -c code
- * 0: for OK. This is the default.
- * 1: for error: Result is the last error
- *
- * -i errorInfo
- * -e errorCode
- * Not applicable for Vim
- *
- * Options may appear in any order, and only the -s option must be
- * present. As with commands, there may be additional options besides
- * these; unknown options are ignored.
- */
-
-/*
- * Maximum size property that can be read at one time by
- * this module:
- */
-
-#define MAX_PROP_WORDS 100000
-
-struct ServerReply
-{
- Window id;
- garray_T strings;
-};
-static garray_T serverReply = { 0, 0, 0, 0, 0 };
-enum ServerReplyOp { SROP_Find, SROP_Add, SROP_Delete };
-
-typedef int (*EndCond) __ARGS((void *));
-
-/*
- * Forward declarations for procedures defined later in this file:
- */
-
-static Window LookupName __ARGS((Display *dpy, char_u *name, int delete, char_u **loose));
-static int SendInit __ARGS((Display *dpy));
-static int DoRegisterName __ARGS((Display *dpy, char_u *name));
-static void DeleteAnyLingerer __ARGS((Display *dpy, Window w));
-static int GetRegProp __ARGS((Display *dpy, char_u **regPropp, long_u *numItemsp, int domsg));
-static int WaitForPend __ARGS((void *p));
-static int WaitForReply __ARGS((void *p));
-static int WindowValid __ARGS((Display *dpy, Window w));
-static void ServerWait __ARGS((Display *dpy, Window w, EndCond endCond, void *endData, int localLoop, int seconds));
-static struct ServerReply *ServerReplyFind __ARGS((Window w, enum ServerReplyOp op));
-static int AppendPropCarefully __ARGS((Display *display, Window window, Atom property, char_u *value, int length));
-static int x_error_check __ARGS((Display *dpy, XErrorEvent *error_event));
-static int IsSerialName __ARGS((char_u *name));
-
-/* Private variables for the "server" functionality */
-static Atom registryProperty = None;
-static Atom vimProperty = None;
-static int got_x_error = FALSE;
-
-static char_u *empty_prop = (char_u *)""; /* empty GetRegProp() result */
-
-/*
- * Associate an ASCII name with Vim. Try real hard to get a unique one.
- * Returns FAIL or OK.
- */
- int
-serverRegisterName(dpy, name)
- Display *dpy; /* display to register with */
- char_u *name; /* the name that will be used as a base */
-{
- int i;
- int res;
- char_u *p = NULL;
-
- res = DoRegisterName(dpy, name);
- if (res < 0)
- {
- i = 1;
- do
- {
- if (res < -1 || i >= 1000)
- {
- MSG_ATTR(_("Unable to register a command server name"),
- hl_attr(HLF_W));
- return FAIL;
- }
- if (p == NULL)
- p = alloc(STRLEN(name) + 10);
- if (p == NULL)
- {
- res = -10;
- continue;
- }
- sprintf((char *)p, "%s%d", name, i++);
- res = DoRegisterName(dpy, p);
- }
- while (res < 0)
- ;
- vim_free(p);
- }
- return OK;
-}
-
- static int
-DoRegisterName(dpy, name)
- Display *dpy;
- char_u *name;
-{
- Window w;
- XErrorHandler old_handler;
-#define MAX_NAME_LENGTH 100
- char_u propInfo[MAX_NAME_LENGTH + 20];
-
- if (commProperty == None)
- {
- if (SendInit(dpy) < 0)
- return -2;
- }
-
- /*
- * Make sure the name is unique, and append info about it to
- * the registry property. It's important to lock the server
- * here to prevent conflicting changes to the registry property.
- * WARNING: Do not step through this while debugging, it will hangup the X
- * server!
- */
- XGrabServer(dpy);
- w = LookupName(dpy, name, FALSE, NULL);
- if (w != (Window)0)
- {
- Status status;
- int dummyInt;
- unsigned int dummyUns;
- Window dummyWin;
-
- /*
- * The name is currently registered. See if the commWindow
- * associated with the name exists. If not, or if the commWindow
- * is *our* commWindow, then just unregister the old name (this
- * could happen if an application dies without cleaning up the
- * registry).
- */
- old_handler = XSetErrorHandler(x_error_check);
- status = XGetGeometry(dpy, w, &dummyWin, &dummyInt, &dummyInt,
- &dummyUns, &dummyUns, &dummyUns, &dummyUns);
- (void)XSetErrorHandler(old_handler);
- if (status != Success && w != commWindow)
- {
- XUngrabServer(dpy);
- XFlush(dpy);
- return -1;
- }
- (void)LookupName(dpy, name, /*delete=*/TRUE, NULL);
- }
- sprintf((char *)propInfo, "%x %.*s", (int_u)commWindow,
- MAX_NAME_LENGTH, name);
- old_handler = XSetErrorHandler(x_error_check);
- got_x_error = FALSE;
- XChangeProperty(dpy, RootWindow(dpy, 0), registryProperty, XA_STRING, 8,
- PropModeAppend, propInfo, STRLEN(propInfo) + 1);
- XUngrabServer(dpy);
- XSync(dpy, False);
- (void)XSetErrorHandler(old_handler);
-
- if (!got_x_error)
- {
-#ifdef FEAT_EVAL
- set_vim_var_string(VV_SEND_SERVER, name, -1);
-#endif
- serverName = vim_strsave(name);
-#ifdef FEAT_TITLE
- need_maketitle = TRUE;
-#endif
- return 0;
- }
- return -2;
-}
-
-#if defined(FEAT_GUI) || defined(PROTO)
-/*
- * Clean out new ID from registry and set it as comm win.
- * Change any registered window ID.
- */
- void
-serverChangeRegisteredWindow(dpy, newwin)
- Display *dpy; /* Display to register with */
- Window newwin; /* Re-register to this ID */
-{
- char_u propInfo[MAX_NAME_LENGTH + 20];
-
- commWindow = newwin;
-
- /* Always call SendInit() here, to make sure commWindow is marked as a Vim
- * window. */
- if (SendInit(dpy) < 0)
- return;
-
- /* WARNING: Do not step through this while debugging, it will hangup the X
- * server! */
- XGrabServer(dpy);
- DeleteAnyLingerer(dpy, newwin);
- if (serverName != NULL)
- {
- /* Reinsert name if we was already registered */
- (void)LookupName(dpy, serverName, /*delete=*/TRUE, NULL);
- sprintf((char *)propInfo, "%x %.*s",
- (int_u)newwin, MAX_NAME_LENGTH, serverName);
- XChangeProperty(dpy, RootWindow(dpy, 0), registryProperty, XA_STRING, 8,
- PropModeAppend, (char_u *)propInfo,
- STRLEN(propInfo) + 1);
- }
- XUngrabServer(dpy);
-}
-#endif
-
-/*
- * Send to an instance of Vim via the X display.
- * Returns 0 for OK, negative for an error.
- */
- int
-serverSendToVim(dpy, name, cmd, result, server, asExpr, localLoop, silent)
- Display *dpy; /* Where to send. */
- char_u *name; /* Where to send. */
- char_u *cmd; /* What to send. */
- char_u **result; /* Result of eval'ed expression */
- Window *server; /* Actual ID of receiving app */
- Bool asExpr; /* Interpret as keystrokes or expr ? */
- Bool localLoop; /* Throw away everything but result */
- int silent; /* don't complain about no server */
-{
- Window w;
- char_u *property;
- int length;
- int res;
- static int serial = 0; /* Running count of sent commands.
- * Used to give each command a
- * different serial number. */
- PendingCommand pending;
- char_u *loosename = NULL;
-
- if (result != NULL)
- *result = NULL;
- if (name == NULL || *name == NUL)
- name = (char_u *)"GVIM"; /* use a default name */
-
- if (commProperty == None && dpy != NULL)
- {
- if (SendInit(dpy) < 0)
- return -1;
- }
-
- /* Execute locally if no display or target is ourselves */
- if (dpy == NULL || (serverName != NULL && STRICMP(name, serverName) == 0))
- {
- if (asExpr)
- {
- char_u *ret;
-
- ret = eval_client_expr_to_string(cmd);
- if (result != NULL)
- {
- if (ret == NULL)
- *result = vim_strsave((char_u *)_(e_invexprmsg));
- else
- *result = ret;
- }
- else
- vim_free(ret);
- return ret == NULL ? -1 : 0;
- }
- else
- server_to_input_buf(cmd);
- return 0;
- }
-
- /*
- * Bind the server name to a communication window.
- *
- * Find any survivor with a serialno attached to the name if the
- * original registrant of the wanted name is no longer present.
- *
- * Delete any lingering names from dead editors.
- */
- while (TRUE)
- {
- w = LookupName(dpy, name, FALSE, &loosename);
- /* Check that the window is hot */
- if (w != None)
- {
- if (!WindowValid(dpy, w))
- {
- LookupName(dpy, loosename ? loosename : name,
- /*DELETE=*/TRUE, NULL);
- continue;
- }
- }
- break;
- }
- if (w == None)
- {
- if (!silent)
- EMSG2(_(e_noserver), name);
- return -1;
- }
- else if (loosename != NULL)
- name = loosename;
- if (server != NULL)
- *server = w;
-
- /*
- * Send the command to target interpreter by appending it to the
- * comm window in the communication window.
- * Length must be computed exactly!
- */
-#ifdef FEAT_MBYTE
- length = STRLEN(name) + STRLEN(p_enc) + STRLEN(cmd) + 14;
-#else
- length = STRLEN(name) + STRLEN(cmd) + 10;
-#endif
- property = (char_u *)alloc((unsigned)length + 30);
-
-#ifdef FEAT_MBYTE
- sprintf((char *)property, "%c%c%c-n %s%c-E %s%c-s %s",
- 0, asExpr ? 'c' : 'k', 0, name, 0, p_enc, 0, cmd);
-#else
- sprintf((char *)property, "%c%c%c-n %s%c-s %s",
- 0, asExpr ? 'c' : 'k', 0, name, 0, cmd);
-#endif
- if (name == loosename)
- vim_free(loosename);
- /* Add a back reference to our comm window */
- serial++;
- sprintf((char *)property + length, "%c-r %x %d",
- 0, (int_u)commWindow, serial);
- /* Add length of what "-r %x %d" resulted in, skipping the NUL. */
- length += STRLEN(property + length + 1) + 1;
-
- res = AppendPropCarefully(dpy, w, commProperty, property, length + 1);
- vim_free(property);
- if (res < 0)
- {
- EMSG(_("E248: Failed to send command to the destination program"));
- return -1;
- }
-
- if (!asExpr) /* There is no answer for this - Keys are sent async */
- return 0;
-
- /*
- * Register the fact that we're waiting for a command to
- * complete (this is needed by SendEventProc and by
- * AppendErrorProc to pass back the command's results).
- */
- pending.serial = serial;
- pending.code = 0;
- pending.result = NULL;
- pending.nextPtr = pendingCommands;
- pendingCommands = &pending;
-
- ServerWait(dpy, w, WaitForPend, &pending, localLoop, 600);
-
- /*
- * Unregister the information about the pending command
- * and return the result.
- */
- if (pendingCommands == &pending)
- pendingCommands = pending.nextPtr;
- else
- {
- PendingCommand *pcPtr;
-
- for (pcPtr = pendingCommands; pcPtr != NULL; pcPtr = pcPtr->nextPtr)
- if (pcPtr->nextPtr == &pending)
- {
- pcPtr->nextPtr = pending.nextPtr;
- break;
- }
- }
- if (result != NULL)
- *result = pending.result;
- else
- vim_free(pending.result);
-
- return pending.code == 0 ? 0 : -1;
-}
-
- static int
-WaitForPend(p)
- void *p;
-{
- PendingCommand *pending = (PendingCommand *) p;
- return pending->result != NULL;
-}
-
-/*
- * Return TRUE if window "w" exists and has a "Vim" property on it.
- */
- static int
-WindowValid(dpy, w)
- Display *dpy;
- Window w;
-{
- XErrorHandler old_handler;
- Atom *plist;
- int numProp;
- int i;
-
- old_handler = XSetErrorHandler(x_error_check);
- got_x_error = 0;
- plist = XListProperties(dpy, w, &numProp);
- XSync(dpy, False);
- XSetErrorHandler(old_handler);
- if (plist == NULL || got_x_error)
- return FALSE;
-
- for (i = 0; i < numProp; i++)
- if (plist[i] == vimProperty)
- {
- XFree(plist);
- return TRUE;
- }
- XFree(plist);
- return FALSE;
-}
-
-/*
- * Enter a loop processing X events & polling chars until we see a result
- */
- static void
-ServerWait(dpy, w, endCond, endData, localLoop, seconds)
- Display *dpy;
- Window w;
- EndCond endCond;
- void *endData;
- int localLoop;
- int seconds;
-{
- time_t start;
- time_t now;
- time_t lastChk = 0;
- XEvent event;
- XPropertyEvent *e = (XPropertyEvent *)&event;
-# define SEND_MSEC_POLL 50
-
- time(&start);
- while (endCond(endData) == 0)
- {
- time(&now);
- if (seconds >= 0 && (now - start) >= seconds)
- break;
- if (now != lastChk)
- {
- lastChk = now;
- if (!WindowValid(dpy, w))
- break;
- /*
- * Sometimes the PropertyChange event doesn't come.
- * This can be seen in eg: vim -c 'echo remote_expr("gvim", "3+2")'
- */
- serverEventProc(dpy, NULL);
- }
- if (localLoop)
- {
- /* Just look out for the answer without calling back into Vim */
-#ifndef HAVE_SELECT
- struct pollfd fds;
-
- fds.fd = ConnectionNumber(dpy);
- fds.events = POLLIN;
- if (poll(&fds, 1, SEND_MSEC_POLL) < 0)
- break;
-#else
- fd_set fds;
- struct timeval tv;
-
- tv.tv_sec = 0;
- tv.tv_usec = SEND_MSEC_POLL * 1000;
- FD_ZERO(&fds);
- FD_SET(ConnectionNumber(dpy), &fds);
- if (select(ConnectionNumber(dpy) + 1, &fds, NULL, NULL, &tv) < 0)
- break;
-#endif
- while (XEventsQueued(dpy, QueuedAfterReading) > 0)
- {
- XNextEvent(dpy, &event);
- if (event.type == PropertyNotify && e->window == commWindow)
- serverEventProc(dpy, &event);
- }
- }
- else
- {
- if (got_int)
- break;
- ui_delay((long)SEND_MSEC_POLL, TRUE);
- ui_breakcheck();
- }
- }
-}
-
-
-/*
- * Fetch a list of all the Vim instance names currently registered for the
- * display.
- *
- * Returns a newline separated list in allocated memory or NULL.
- */
- char_u *
-serverGetVimNames(dpy)
- Display *dpy;
-{
- char_u *regProp;
- char_u *entry;
- char_u *p;
- long_u numItems;
- int_u w;
- garray_T ga;
-
- if (registryProperty == None)
- {
- if (SendInit(dpy) < 0)
- return NULL;
- }
- ga_init2(&ga, 1, 100);
-
- /*
- * Read the registry property.
- */
- if (GetRegProp(dpy, &regProp, &numItems, TRUE) == FAIL)
- return NULL;
-
- /*
- * Scan all of the names out of the property.
- */
- ga_init2(&ga, 1, 100);
- for (p = regProp; (long_u)(p - regProp) < numItems; p++)
- {
- entry = p;
- while (*p != 0 && !isspace(*p))
- p++;
- if (*p != 0)
- {
- w = None;
- sscanf((char *)entry, "%x", &w);
- if (WindowValid(dpy, (Window)w))
- {
- ga_concat(&ga, p + 1);
- ga_concat(&ga, (char_u *)"\n");
- }
- while (*p != 0)
- p++;
- }
- }
- if (regProp != empty_prop)
- XFree(regProp);
- ga_append(&ga, NUL);
- return ga.ga_data;
-}
-
-/* ----------------------------------------------------------
- * Reply stuff
- */
-
- static struct ServerReply *
-ServerReplyFind(w, op)
- Window w;
- enum ServerReplyOp op;
-{
- struct ServerReply *p;
- struct ServerReply e;
- int i;
-
- p = (struct ServerReply *) serverReply.ga_data;
- for (i = 0; i < serverReply.ga_len; i++, p++)
- if (p->id == w)
- break;
- if (i >= serverReply.ga_len)
- p = NULL;
-
- if (p == NULL && op == SROP_Add)
- {
- if (serverReply.ga_growsize == 0)
- ga_init2(&serverReply, sizeof(struct ServerReply), 1);
- if (ga_grow(&serverReply, 1) == OK)
- {
- p = ((struct ServerReply *) serverReply.ga_data)
- + serverReply.ga_len;
- e.id = w;
- ga_init2(&e.strings, 1, 100);
- mch_memmove(p, &e, sizeof(e));
- serverReply.ga_len++;
- }
- }
- else if (p != NULL && op == SROP_Delete)
- {
- ga_clear(&p->strings);
- mch_memmove(p, p + 1, (serverReply.ga_len - i - 1) * sizeof(*p));
- serverReply.ga_len--;
- }
-
- return p;
-}
-
-/*
- * Convert string to windowid.
- * Issue an error if the id is invalid.
- */
- Window
-serverStrToWin(str)
- char_u *str;
-{
- unsigned id = None;
-
- sscanf((char *)str, "0x%x", &id);
- if (id == None)
- EMSG2(_("E573: Invalid server id used: %s"), str);
-
- return (Window)id;
-}
-
-/*
- * Send a reply string (notification) to client with id "name".
- * Return -1 if the window is invalid.
- */
- int
-serverSendReply(name, str)
- char_u *name;
- char_u *str;
-{
- char_u *property;
- int length;
- int res;
- Display *dpy = X_DISPLAY;
- Window win = serverStrToWin(name);
-
- if (commProperty == None)
- {
- if (SendInit(dpy) < 0)
- return -2;
- }
- if (!WindowValid(dpy, win))
- return -1;
-
-#ifdef FEAT_MBYTE
- length = STRLEN(p_enc) + STRLEN(str) + 14;
-#else
- length = STRLEN(str) + 10;
-#endif
- if ((property = (char_u *)alloc((unsigned)length + 30)) != NULL)
- {
-#ifdef FEAT_MBYTE
- sprintf((char *)property, "%cn%c-E %s%c-n %s%c-w %x",
- 0, 0, p_enc, 0, str, 0, (unsigned int)commWindow);
-#else
- sprintf((char *)property, "%cn%c-n %s%c-w %x",
- 0, 0, str, 0, (unsigned int)commWindow);
-#endif
- /* Add length of what "%x" resulted in. */
- length += STRLEN(property + length);
- res = AppendPropCarefully(dpy, win, commProperty, property, length + 1);
- vim_free(property);
- return res;
- }
- return -1;
-}
-
- static int
-WaitForReply(p)
- void *p;
-{
- Window *w = (Window *) p;
- return ServerReplyFind(*w, SROP_Find) != NULL;
-}
-
-/*
- * Wait for replies from id (win)
- * Return 0 and the malloc'ed string when a reply is available.
- * Return -1 if the window becomes invalid while waiting.
- */
- int
-serverReadReply(dpy, win, str, localLoop)
- Display *dpy;
- Window win;
- char_u **str;
- int localLoop;
-{
- int len;
- char_u *s;
- struct ServerReply *p;
-
- ServerWait(dpy, win, WaitForReply, &win, localLoop, -1);
-
- if ((p = ServerReplyFind(win, SROP_Find)) != NULL && p->strings.ga_len > 0)
- {
- *str = vim_strsave(p->strings.ga_data);
- len = STRLEN(*str) + 1;
- if (len < p->strings.ga_len)
- {
- s = (char_u *) p->strings.ga_data;
- mch_memmove(s, s + len, p->strings.ga_len - len);
- p->strings.ga_len -= len;
- }
- else
- {
- /* Last string read. Remove from list */
- ga_clear(&p->strings);
- ServerReplyFind(win, SROP_Delete);
- }
- return 0;
- }
- return -1;
-}
-
-/*
- * Check for replies from id (win).
- * Return TRUE and a non-malloc'ed string if there is. Else return FALSE.
- */
- int
-serverPeekReply(dpy, win, str)
- Display *dpy;
- Window win;
- char_u **str;
-{
- struct ServerReply *p;
-
- if ((p = ServerReplyFind(win, SROP_Find)) != NULL && p->strings.ga_len > 0)
- {
- if (str != NULL)
- *str = p->strings.ga_data;
- return 1;
- }
- if (!WindowValid(dpy, win))
- return -1;
- return 0;
-}
-
-
-/*
- * Initialize the communication channels for sending commands and receiving
- * results.
- */
- static int
-SendInit(dpy)
- Display *dpy;
-{
- XErrorHandler old_handler;
-
- /*
- * Create the window used for communication, and set up an
- * event handler for it.
- */
- old_handler = XSetErrorHandler(x_error_check);
- got_x_error = FALSE;
-
- if (commProperty == None)
- commProperty = XInternAtom(dpy, "Comm", False);
- if (vimProperty == None)
- vimProperty = XInternAtom(dpy, "Vim", False);
- if (registryProperty == None)
- registryProperty = XInternAtom(dpy, "VimRegistry", False);
-
- if (commWindow == None)
- {
- commWindow = XCreateSimpleWindow(dpy, XDefaultRootWindow(dpy),
- getpid(), 0, 10, 10, 0,
- WhitePixel(dpy, DefaultScreen(dpy)),
- WhitePixel(dpy, DefaultScreen(dpy)));
- XSelectInput(dpy, commWindow, PropertyChangeMask);
- /* WARNING: Do not step through this while debugging, it will hangup
- * the X server! */
- XGrabServer(dpy);
- DeleteAnyLingerer(dpy, commWindow);
- XUngrabServer(dpy);
- }
-
- /* Make window recognizable as a vim window */
- XChangeProperty(dpy, commWindow, vimProperty, XA_STRING,
- 8, PropModeReplace, (char_u *)VIM_VERSION_SHORT,
- (int)STRLEN(VIM_VERSION_SHORT) + 1);
-
- XSync(dpy, False);
- (void)XSetErrorHandler(old_handler);
-
- return got_x_error ? -1 : 0;
-}
-
-/*
- * Given a server name, see if the name exists in the registry for a
- * particular display.
- *
- * If the given name is registered, return the ID of the window associated
- * with the name. If the name isn't registered, then return 0.
- *
- * Side effects:
- * If the registry property is improperly formed, then it is deleted.
- * If "delete" is non-zero, then if the named server is found it is
- * removed from the registry property.
- */
- static Window
-LookupName(dpy, name, delete, loose)
- Display *dpy; /* Display whose registry to check. */
- char_u *name; /* Name of a server. */
- int delete; /* If non-zero, delete info about name. */
- char_u **loose; /* Do another search matching -999 if not found
- Return result here if a match is found */
-{
- char_u *regProp, *entry;
- char_u *p;
- long_u numItems;
- int_u returnValue;
-
- /*
- * Read the registry property.
- */
- if (GetRegProp(dpy, &regProp, &numItems, FALSE) == FAIL)
- return 0;
-
- /*
- * Scan the property for the desired name.
- */
- returnValue = (int_u)None;
- entry = NULL; /* Not needed, but eliminates compiler warning. */
- for (p = regProp; (long_u)(p - regProp) < numItems; )
- {
- entry = p;
- while (*p != 0 && !isspace(*p))
- p++;
- if (*p != 0 && STRICMP(name, p + 1) == 0)
- {
- sscanf((char *)entry, "%x", &returnValue);
- break;
- }
- while (*p != 0)
- p++;
- p++;
- }
-
- if (loose != NULL && returnValue == (int_u)None && !IsSerialName(name))
- {
- for (p = regProp; (long_u)(p - regProp) < numItems; )
- {
- entry = p;
- while (*p != 0 && !isspace(*p))
- p++;
- if (*p != 0 && IsSerialName(p + 1)
- && STRNICMP(name, p + 1, STRLEN(name)) == 0)
- {
- sscanf((char *)entry, "%x", &returnValue);
- *loose = vim_strsave(p + 1);
- break;
- }
- while (*p != 0)
- p++;
- p++;
- }
- }
-
- /*
- * Delete the property, if that is desired (copy down the
- * remainder of the registry property to overlay the deleted
- * info, then rewrite the property).
- */
- if (delete && returnValue != (int_u)None)
- {
- int count;
-
- while (*p != 0)
- p++;
- p++;
- count = numItems - (p - regProp);
- if (count > 0)
- mch_memmove(entry, p, count);
- XChangeProperty(dpy, RootWindow(dpy, 0), registryProperty, XA_STRING,
- 8, PropModeReplace, regProp,
- (int)(numItems - (p - entry)));
- XSync(dpy, False);
- }
-
- if (regProp != empty_prop)
- XFree(regProp);
- return (Window)returnValue;
-}
-
-/*
- * Delete any lingering occurrence of window id. We promise that any
- * occurrence is not ours since it is not yet put into the registry (by us)
- *
- * This is necessary in the following scenario:
- * 1. There is an old windowid for an exit'ed vim in the registry
- * 2. We get that id for our commWindow but only want to send, not register.
- * 3. The window will mistakenly be regarded valid because of own commWindow
- */
- static void
-DeleteAnyLingerer(dpy, win)
- Display *dpy; /* Display whose registry to check. */
- Window win; /* Window to remove */
-{
- char_u *regProp, *entry = NULL;
- char_u *p;
- long_u numItems;
- int_u wwin;
-
- /*
- * Read the registry property.
- */
- if (GetRegProp(dpy, &regProp, &numItems, FALSE) == FAIL)
- return;
-
- /* Scan the property for the window id. */
- for (p = regProp; (long_u)(p - regProp) < numItems; )
- {
- if (*p != 0)
- {
- sscanf((char *)p, "%x", &wwin);
- if ((Window)wwin == win)
- {
- int lastHalf;
-
- /* Copy down the remainder to delete entry */
- entry = p;
- while (*p != 0)
- p++;
- p++;
- lastHalf = numItems - (p - regProp);
- if (lastHalf > 0)
- mch_memmove(entry, p, lastHalf);
- numItems = (entry - regProp) + lastHalf;
- p = entry;
- continue;
- }
- }
- while (*p != 0)
- p++;
- p++;
- }
-
- if (entry != NULL)
- {
- XChangeProperty(dpy, RootWindow(dpy, 0), registryProperty,
- XA_STRING, 8, PropModeReplace, regProp,
- (int)(p - regProp));
- XSync(dpy, False);
- }
-
- if (regProp != empty_prop)
- XFree(regProp);
-}
-
-/*
- * Read the registry property. Delete it when it's formatted wrong.
- * Return the property in "regPropp". "empty_prop" is used when it doesn't
- * exist yet.
- * Return OK when successful.
- */
- static int
-GetRegProp(dpy, regPropp, numItemsp, domsg)
- Display *dpy;
- char_u **regPropp;
- long_u *numItemsp;
- int domsg; /* When TRUE give error message. */
-{
- int result, actualFormat;
- long_u bytesAfter;
- Atom actualType;
- XErrorHandler old_handler;
-
- *regPropp = NULL;
- old_handler = XSetErrorHandler(x_error_check);
- got_x_error = FALSE;
-
- result = XGetWindowProperty(dpy, RootWindow(dpy, 0), registryProperty, 0L,
- (long)MAX_PROP_WORDS, False,
- XA_STRING, &actualType,
- &actualFormat, numItemsp, &bytesAfter,
- regPropp);
-
- XSync(dpy, FALSE);
- (void)XSetErrorHandler(old_handler);
- if (got_x_error)
- return FAIL;
-
- if (actualType == None)
- {
- /* No prop yet. Logically equal to the empty list */
- *numItemsp = 0;
- *regPropp = empty_prop;
- return OK;
- }
-
- /* If the property is improperly formed, then delete it. */
- if (result != Success || actualFormat != 8 || actualType != XA_STRING)
- {
- if (*regPropp != NULL)
- XFree(*regPropp);
- XDeleteProperty(dpy, RootWindow(dpy, 0), registryProperty);
- if (domsg)
- EMSG(_("E251: VIM instance registry property is badly formed. Deleted!"));
- return FAIL;
- }
- return OK;
-}
-
-/*
- * This procedure is invoked by the various X event loops throughout Vims when
- * a property changes on the communication window. This procedure reads the
- * property and handles command requests and responses.
- */
- void
-serverEventProc(dpy, eventPtr)
- Display *dpy;
- XEvent *eventPtr; /* Information about event. */
-{
- char_u *propInfo;
- char_u *p;
- int result, actualFormat, code;
- long_u numItems, bytesAfter;
- Atom actualType;
- char_u *tofree;
-
- if (eventPtr != NULL)
- {
- if (eventPtr->xproperty.atom != commProperty
- || eventPtr->xproperty.state != PropertyNewValue)
- return;
- }
-
- /*
- * Read the comm property and delete it.
- */
- propInfo = NULL;
- result = XGetWindowProperty(dpy, commWindow, commProperty, 0L,
- (long)MAX_PROP_WORDS, True,
- XA_STRING, &actualType,
- &actualFormat, &numItems, &bytesAfter,
- &propInfo);
-
- /* If the property doesn't exist or is improperly formed then ignore it. */
- if (result != Success || actualType != XA_STRING || actualFormat != 8)
- {
- if (propInfo != NULL)
- XFree(propInfo);
- return;
- }
-
- /*
- * Several commands and results could arrive in the property at
- * one time; each iteration through the outer loop handles a
- * single command or result.
- */
- for (p = propInfo; (long_u)(p - propInfo) < numItems; )
- {
- /*
- * Ignore leading NULs; each command or result starts with a
- * NUL so that no matter how badly formed a preceding command
- * is, we'll be able to tell that a new command/result is
- * starting.
- */
- if (*p == 0)
- {
- p++;
- continue;
- }
-
- if ((*p == 'c' || *p == 'k') && (p[1] == 0))
- {
- Window resWindow;
- char_u *name, *script, *serial, *end, *res;
- Bool asKeys = *p == 'k';
- garray_T reply;
- char_u *enc;
-
- /*
- * This is an incoming command from some other application.
- * Iterate over all of its options. Stop when we reach
- * the end of the property or something that doesn't look
- * like an option.
- */
- p += 2;
- name = NULL;
- resWindow = None;
- serial = (char_u *)"";
- script = NULL;
- enc = NULL;
- while ((long_u)(p - propInfo) < numItems && *p == '-')
- {
- switch (p[1])
- {
- case 'r':
- end = skipwhite(p + 2);
- resWindow = 0;
- while (vim_isxdigit(*end))
- {
- resWindow = 16 * resWindow + (long_u)hex2nr(*end);
- ++end;
- }
- if (end == p + 2 || *end != ' ')
- resWindow = None;
- else
- {
- p = serial = end + 1;
- clientWindow = resWindow; /* Remember in global */
- }
- break;
- case 'n':
- if (p[2] == ' ')
- name = p + 3;
- break;
- case 's':
- if (p[2] == ' ')
- script = p + 3;
- break;
- case 'E':
- if (p[2] == ' ')
- enc = p + 3;
- break;
- }
- while (*p != 0)
- p++;
- p++;
- }
-
- if (script == NULL || name == NULL)
- continue;
-
- /*
- * Initialize the result property, so that we're ready at any
- * time if we need to return an error.
- */
- if (resWindow != None)
- {
- ga_init2(&reply, 1, 100);
-#ifdef FEAT_MBYTE
- ga_grow(&reply, 50 + STRLEN(p_enc));
- sprintf(reply.ga_data, "%cr%c-E %s%c-s %s%c-r ",
- 0, 0, p_enc, 0, serial, 0);
- reply.ga_len = 14 + STRLEN(p_enc) + STRLEN(serial);
-#else
- ga_grow(&reply, 50);
- sprintf(reply.ga_data, "%cr%c-s %s%c-r ", 0, 0, serial, 0);
- reply.ga_len = 10 + STRLEN(serial);
-#endif
- }
- res = NULL;
- if (serverName != NULL && STRICMP(name, serverName) == 0)
- {
- script = serverConvert(enc, script, &tofree);
- if (asKeys)
- server_to_input_buf(script);
- else
- res = eval_client_expr_to_string(script);
- vim_free(tofree);
- }
- if (resWindow != None)
- {
- if (res != NULL)
- ga_concat(&reply, res);
- else if (asKeys == 0)
- {
- ga_concat(&reply, (char_u *)_(e_invexprmsg));
- ga_append(&reply, 0);
- ga_concat(&reply, (char_u *)"-c 1");
- }
- ga_append(&reply, NUL);
- (void)AppendPropCarefully(dpy, resWindow, commProperty,
- reply.ga_data, reply.ga_len);
- ga_clear(&reply);
- }
- vim_free(res);
- }
- else if (*p == 'r' && p[1] == 0)
- {
- int serial, gotSerial;
- char_u *res;
- PendingCommand *pcPtr;
- char_u *enc;
-
- /*
- * This is a reply to some command that we sent out. Iterate
- * over all of its options. Stop when we reach the end of the
- * property or something that doesn't look like an option.
- */
- p += 2;
- gotSerial = 0;
- res = (char_u *)"";
- code = 0;
- enc = NULL;
- while ((long_u)(p - propInfo) < numItems && *p == '-')
- {
- switch (p[1])
- {
- case 'r':
- if (p[2] == ' ')
- res = p + 3;
- break;
- case 'E':
- if (p[2] == ' ')
- enc = p + 3;
- break;
- case 's':
- if (sscanf((char *)p + 2, " %d", &serial) == 1)
- gotSerial = 1;
- break;
- case 'c':
- if (sscanf((char *)p + 2, " %d", &code) != 1)
- code = 0;
- break;
- }
- while (*p != 0)
- p++;
- p++;
- }
-
- if (!gotSerial)
- continue;
-
- /*
- * Give the result information to anyone who's
- * waiting for it.
- */
- for (pcPtr = pendingCommands; pcPtr != NULL; pcPtr = pcPtr->nextPtr)
- {
- if (serial != pcPtr->serial || pcPtr->result != NULL)
- continue;
-
- pcPtr->code = code;
- if (res != NULL)
- {
- res = serverConvert(enc, res, &tofree);
- if (tofree == NULL)
- res = vim_strsave(res);
- pcPtr->result = res;
- }
- else
- pcPtr->result = vim_strsave((char_u *)"");
- break;
- }
- }
- else if (*p == 'n' && p[1] == 0)
- {
- Window win = 0;
- unsigned int u;
- int gotWindow;
- char_u *str;
- struct ServerReply *r;
- char_u *enc;
-
- /*
- * This is a (n)otification. Sent with serverreply_send in VimL.
- * Execute any autocommand and save it for later retrieval
- */
- p += 2;
- gotWindow = 0;
- str = (char_u *)"";
- enc = NULL;
- while ((long_u)(p - propInfo) < numItems && *p == '-')
- {
- switch (p[1])
- {
- case 'n':
- if (p[2] == ' ')
- str = p + 3;
- break;
- case 'E':
- if (p[2] == ' ')
- enc = p + 3;
- break;
- case 'w':
- if (sscanf((char *)p + 2, " %x", &u) == 1)
- {
- win = u;
- gotWindow = 1;
- }
- break;
- }
- while (*p != 0)
- p++;
- p++;
- }
-
- if (!gotWindow)
- continue;
- str = serverConvert(enc, str, &tofree);
- if ((r = ServerReplyFind(win, SROP_Add)) != NULL)
- {
- ga_concat(&(r->strings), str);
- ga_append(&(r->strings), NUL);
- }
-#ifdef FEAT_AUTOCMD
- {
- char_u winstr[30];
-
- sprintf((char *)winstr, "0x%x", (unsigned int)win);
- apply_autocmds(EVENT_REMOTEREPLY, winstr, str, TRUE, curbuf);
- }
-#endif
- vim_free(tofree);
- }
- else
- {
- /*
- * Didn't recognize this thing. Just skip through the next
- * null character and try again.
- * Even if we get an 'r'(eply) we will throw it away as we
- * never specify (and thus expect) one
- */
- while (*p != 0)
- p++;
- p++;
- }
- }
- XFree(propInfo);
-}
-
-/*
- * Append a given property to a given window, but set up an X error handler so
- * that if the append fails this procedure can return an error code rather
- * than having Xlib panic.
- * Return: 0 for OK, -1 for error
- */
- static int
-AppendPropCarefully(dpy, window, property, value, length)
- Display *dpy; /* Display on which to operate. */
- Window window; /* Window whose property is to be modified. */
- Atom property; /* Name of property. */
- char_u *value; /* Characters to append to property. */
- int length; /* How much to append */
-{
- XErrorHandler old_handler;
-
- old_handler = XSetErrorHandler(x_error_check);
- got_x_error = FALSE;
- XChangeProperty(dpy, window, property, XA_STRING, 8,
- PropModeAppend, value, length);
- XSync(dpy, False);
- (void) XSetErrorHandler(old_handler);
- return got_x_error ? -1 : 0;
-}
-
-
-/*
- * Another X Error handler, just used to check for errors.
- */
- static int
-x_error_check(dpy, error_event)
- Display *dpy UNUSED;
- XErrorEvent *error_event UNUSED;
-{
- got_x_error = TRUE;
- return 0;
-}
-
-/*
- * Check if "str" looks like it had a serial number appended.
- * Actually just checks if the name ends in a digit.
- */
- static int
-IsSerialName(str)
- char_u *str;
-{
- int len = STRLEN(str);
-
- return (len > 1 && vim_isdigit(str[len - 1]));
-}
-#endif /* FEAT_CLIENTSERVER */
diff -r 15b934a16641 -r 2082fc32d223 src/main.c
--- a/src/main.c Wed Sep 14 19:04:40 2011 +0200
+++ b/src/main.c Thu Sep 15 21:25:11 2011 +0900
@@ -72,7 +72,6 @@
char_u *serverName_arg; /* cmdline arg for server name */
char_u *serverStr; /* remote server command */
char_u *serverStrEnc; /* encoding of serverStr */
- char_u *servername; /* allocated name for our server */
#endif
#if (!defined(UNIX) && !defined(__EMX__)) || defined(ARCHIE)
int literal; /* don't expand file names */
@@ -3440,13 +3439,10 @@
exec_on_server(parmp)
mparm_T *parmp;
{
+ char_u *servername;
+
if (parmp->serverName_arg == NULL || *parmp->serverName_arg != NUL)
{
-# ifdef WIN32
- /* 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
@@ -3461,18 +3457,17 @@
# endif
}
+ cmdsrv_init();
+
/* 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 WIN32
- if (parmp->servername != NULL)
+ * And register server */
+ servername = serverMakeName(parmp->serverName_arg, parmp->argv[0]);
+ if (servername != NULL)
{
- serverSetName(parmp->servername);
- vim_free(parmp->servername);
+ cmdsrv_register_name(servername);
+ vim_free(servername);
+ TIME_MSG("register server name");
}
-# endif
}
}
@@ -3483,31 +3478,6 @@
prepare_server(parmp)
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.
- * When running as root --servername is also required.
- */
- if (X_DISPLAY != NULL && parmp->servername != NULL && (
-# ifdef FEAT_GUI
- (gui.in_use
-# 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).
@@ -3532,6 +3502,7 @@
char_u *res;
int i;
char_u *sname;
+ char_u *serverid;
int ret;
int didone = FALSE;
int exiterr = 0;
@@ -3545,18 +3516,21 @@
#define ARGTYPE_SEND 3
int silent = FALSE;
int tabs = FALSE;
-# ifndef FEAT_X11
- HWND srv;
-# else
- Window srv;
-
- setup_term_clip();
-# endif
+
+ /* start temporary server to receive reply */
+ if (cmdsrv_init() != 0)
+ return;
+
+ if (cmdsrv_register_name((char_u *)CMDSRV_TMPNAME) != 0)
+ return;
sname = serverMakeName(serverName_arg, argv[0]);
if (sname == NULL)
return;
+ /* If server is not found, show error later. */
+ serverid = cmdsrv_find_server(sname, TRUE);
+
/*
* Execute the command server related arguments and remove them
* from the argc/argv array; We may have to return into main()
@@ -3630,20 +3604,17 @@
}
Argc = i;
}
-# ifdef FEAT_X11
- if (xterm_dpy == NULL)
+ if (serverid == NULL)
{
- mch_errmsg(_("No display"));
+ if (!silent)
+ EMSG2(_(e_noserver), sname);
ret = -1;
}
else
- ret = serverSendToVim(xterm_dpy, sname, *serverStr,
- NULL, &srv, 0, 0, silent);
-# else
- /* Win32 always works? */
- ret = serverSendToVim(sname, *serverStr, NULL, &srv, 0, silent);
-# endif
- if (ret < 0)
+ {
+ ret = cmdsrv_send_keys(serverid, *serverStr);
+ }
+ if (ret != 0)
{
if (argtype == ARGTYPE_SEND)
{
@@ -3660,85 +3631,56 @@
# ifdef FEAT_GUI_W32
/* 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);
+ * server, which we can bring to the foreground here. */
+ if (argtype != ARGTYPE_SEND && TOUPPER_ASC(*serverid) == 'G')
+ cmdsrv_foreground(serverid);
# 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)
+ if (argtype == ARGTYPE_EDIT_WAIT)
{
int numFiles = *argc - i - 1;
int j;
char_u *done = alloc(numFiles);
char_u *p;
-# ifdef FEAT_GUI_W32
- 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_W32
- 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 WIN32
- p = serverGetReply(srv, NULL, TRUE, TRUE);
+ if (cmdsrv_wait_reply(serverid, &p) != 0)
+ break;
if (p == NULL)
break;
-# else
- if (serverReadReply(xterm_dpy, srv, &p, TRUE) < 0)
- break;
-# endif
j = atoi((char *)p);
if (j >= 0 && j < numFiles)
{
-# ifdef FEAT_GUI_W32
- ++count;
- sprintf(ni.szTip, _("%d of %d edited"),
- count, numFiles);
- Shell_NotifyIcon(NIM_MODIFY, &ni);
-# endif
done[j] = 1;
}
}
-# ifdef FEAT_GUI_W32
- 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 WIN32
- /* Win32 always works? */
- if (serverSendToVim(sname, (char_u *)argv[i + 1],
- &res, NULL, 1, 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, 1, FALSE) < 0)
-# endif
+ if (serverid == NULL)
+ {
+ EMSG2(_(e_noserver), sname);
+ ret = -1;
+ }
+ else
+ {
+ ret = cmdsrv_send_expr(serverid, (char_u *)argv[i + 1], &res);
+ }
+ if (ret != 0)
{
if (res != NULL && *res != NUL)
{
@@ -3752,13 +3694,7 @@
}
else if (STRICMP(argv[i], "--serverlist") == 0)
{
-# ifdef WIN32
- /* Win32 always works? */
- res = serverGetVimNames();
-# else
- if (xterm_dpy != NULL)
- res = serverGetVimNames(xterm_dpy);
-# endif
+ cmdsrv_server_list(&res);
if (called_emsg)
mch_errmsg("\n");
}
@@ -3784,6 +3720,8 @@
vim_free(res);
}
+ cmdsrv_uninit();
+
if (didone)
{
display_errors(); /* display any collected messages */
@@ -3793,6 +3731,7 @@
/* Return back into main() */
*argc = newArgC;
vim_free(sname);
+ vim_free(serverid);
}
/*
diff -r 15b934a16641 -r 2082fc32d223 src/misc2.c
--- a/src/misc2.c Wed Sep 14 19:04:40 2011 +0200
+++ b/src/misc2.c Thu Sep 15 21:25:11 2011 +0900
@@ -1185,10 +1185,6 @@
ResetRedobuff();
ResetRedobuff();
-#if defined(FEAT_CLIENTSERVER) && defined(FEAT_X11)
- vim_free(serverDelayedStartName);
-#endif
-
/* highlight info */
free_highlight();
diff -r 15b934a16641 -r 2082fc32d223 src/os_mswin.c
--- a/src/os_mswin.c Wed Sep 14 19:04:40 2011 +0200
+++ b/src/os_mswin.c Thu Sep 15 21:25:11 2011 +0900
@@ -218,6 +218,9 @@
ml_close_all(TRUE); /* remove all memfiles */
+# ifdef FEAT_CLIENTSERVER
+ cmdsrv_uninit();
+# endif
# ifdef FEAT_OLE
UninitOLE();
# endif
@@ -2498,649 +2501,6 @@
}
#endif
-#if defined(FEAT_CLIENTSERVER) || defined(PROTO)
-/*
- * Client-server code for Vim
- *
- * Originally written by Paul Moore
- */
-
-/* In order to handle inter-process messages, we need to have a window. But
- * the functions in this module can be called before the main GUI window is
- * created (and may also be called in the console version, where there is no
- * GUI window at all).
- *
- * So we create a hidden window, and arrange to destroy it on exit.
- */
-HWND message_window = 0; /* window that's handling messsages */
-
-#define VIM_CLASSNAME "VIM_MESSAGES"
-#define VIM_CLASSNAME_LEN (sizeof(VIM_CLASSNAME) - 1)
-
-/* Communication is via WM_COPYDATA messages. The message type is send in
- * the dwData parameter. Types are defined here. */
-#define COPYDATA_KEYS 0
-#define COPYDATA_REPLY 1
-#define COPYDATA_EXPR 10
-#define COPYDATA_RESULT 11
-#define COPYDATA_ERROR_RESULT 12
-#define COPYDATA_ENCODING 20
-
-/* This is a structure containing a server HWND and its name. */
-struct server_id
-{
- HWND hwnd;
- char_u *name;
-};
-
-/* Last received 'encoding' that the client uses. */
-static char_u *client_enc = NULL;
-
-/*
- * Tell the other side what encoding we are using.
- * Errors are ignored.
- */
- static void
-serverSendEnc(HWND target)
-{
- COPYDATASTRUCT data;
-
- data.dwData = COPYDATA_ENCODING;
-#ifdef FEAT_MBYTE
- data.cbData = (DWORD)STRLEN(p_enc) + 1;
- data.lpData = p_enc;
-#else
- data.cbData = (DWORD)STRLEN("latin1") + 1;
- data.lpData = "latin1";
-#endif
- (void)SendMessage(target, WM_COPYDATA, (WPARAM)message_window,
- (LPARAM)(&data));
-}
-
-/*
- * Clean up on exit. This destroys the hidden message window.
- */
- static void
-#ifdef __BORLANDC__
- _RTLENTRYF
-#endif
-CleanUpMessaging(void)
-{
- if (message_window != 0)
- {
- DestroyWindow(message_window);
- message_window = 0;
- }
-}
-
-static int save_reply(HWND server, char_u *reply, int expr);
-
-/*s
- * The window procedure for the hidden message window.
- * It handles callback messages and notifications from servers.
- * In order to process these messages, it is necessary to run a
- * message loop. Code which may run before the main message loop
- * is started (in the GUI) is careful to pump messages when it needs
- * to. Features which require message delivery during normal use will
- * not work in the console version - this basically means those
- * features which allow Vim to act as a server, rather than a client.
- */
- static LRESULT CALLBACK
-Messaging_WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
-{
- if (msg == WM_COPYDATA)
- {
- /* This is a message from another Vim. The dwData member of the
- * COPYDATASTRUCT determines the type of message:
- * COPYDATA_ENCODING:
- * The encoding that the client uses. Following messages will
- * use this encoding, convert if needed.
- * COPYDATA_KEYS:
- * A key sequence. We are a server, and a client wants these keys
- * adding to the input queue.
- * COPYDATA_REPLY:
- * A reply. We are a client, and a server has sent this message
- * in response to a request. (server2client())
- * COPYDATA_EXPR:
- * An expression. We are a server, and a client wants us to
- * evaluate this expression.
- * COPYDATA_RESULT:
- * A reply. We are a client, and a server has sent this message
- * in response to a COPYDATA_EXPR.
- * COPYDATA_ERROR_RESULT:
- * A reply. We are a client, and a server has sent this message
- * in response to a COPYDATA_EXPR that failed to evaluate.
- */
- COPYDATASTRUCT *data = (COPYDATASTRUCT*)lParam;
- HWND sender = (HWND)wParam;
- COPYDATASTRUCT reply;
- char_u *res;
- char_u winstr[30];
- int retval;
- char_u *str;
- char_u *tofree;
-
- switch (data->dwData)
- {
- case COPYDATA_ENCODING:
-# ifdef FEAT_MBYTE
- /* Remember the encoding that the client uses. */
- vim_free(client_enc);
- client_enc = enc_canonize((char_u *)data->lpData);
-# endif
- return 1;
-
- case COPYDATA_KEYS:
- /* Remember who sent this, for <client> */
- clientWindow = sender;
-
- /* Add the received keys to the input buffer. The loop waiting
- * for the user to do something should check the input buffer. */
- str = serverConvert(client_enc, (char_u *)data->lpData, &tofree);
- server_to_input_buf(str);
- vim_free(tofree);
-
-# ifdef FEAT_GUI
- /* Wake up the main GUI loop. */
- if (s_hwnd != 0)
- PostMessage(s_hwnd, WM_NULL, 0, 0);
-# endif
- return 1;
-
- case COPYDATA_EXPR:
- /* Remember who sent this, for <client> */
- clientWindow = sender;
-
- str = serverConvert(client_enc, (char_u *)data->lpData, &tofree);
- res = eval_client_expr_to_string(str);
- vim_free(tofree);
-
- if (res == NULL)
- {
- res = vim_strsave(_(e_invexprmsg));
- reply.dwData = COPYDATA_ERROR_RESULT;
- }
- else
- reply.dwData = COPYDATA_RESULT;
- reply.lpData = res;
- reply.cbData = (DWORD)STRLEN(res) + 1;
-
- serverSendEnc(sender);
- retval = (int)SendMessage(sender, WM_COPYDATA, (WPARAM)message_window,
- (LPARAM)(&reply));
- vim_free(res);
- return retval;
-
- case COPYDATA_REPLY:
- case COPYDATA_RESULT:
- case COPYDATA_ERROR_RESULT:
- if (data->lpData != NULL)
- {
- str = serverConvert(client_enc, (char_u *)data->lpData,
- &tofree);
- if (tofree == NULL)
- str = vim_strsave(str);
- if (save_reply(sender, str,
- (data->dwData == COPYDATA_REPLY ? 0 :
- (data->dwData == COPYDATA_RESULT ? 1 :
- 2))) == FAIL)
- vim_free(str);
-#ifdef FEAT_AUTOCMD
- else if (data->dwData == COPYDATA_REPLY)
- {
- sprintf((char *)winstr, PRINTF_HEX_LONG_U, (long_u)sender);
- apply_autocmds(EVENT_REMOTEREPLY, winstr, str,
- TRUE, curbuf);
- }
-#endif
- }
- return 1;
- }
-
- return 0;
- }
-
- else if (msg == WM_ACTIVATE && wParam == WA_ACTIVE)
- {
- /* When the message window is activated (brought to the foreground),
- * this actually applies to the text window. */
-#ifndef FEAT_GUI
- GetConsoleHwnd(); /* get value of s_hwnd */
-#endif
- if (s_hwnd != 0)
- {
- SetForegroundWindow(s_hwnd);
- return 0;
- }
- }
-
- return DefWindowProc(hwnd, msg, wParam, lParam);
-}
-
-/*
- * Initialise the message handling process. This involves creating a window
- * to handle messages - the window will not be visible.
- */
- void
-serverInitMessaging(void)
-{
- WNDCLASS wndclass;
- HINSTANCE s_hinst;
-
- /* Clean up on exit */
- atexit(CleanUpMessaging);
-
- /* Register a window class - we only really care
- * about the window procedure
- */
- s_hinst = (HINSTANCE)GetModuleHandle(0);
- wndclass.style = 0;
- wndclass.lpfnWndProc = Messaging_WndProc;
- wndclass.cbClsExtra = 0;
- wndclass.cbWndExtra = 0;
- wndclass.hInstance = s_hinst;
- wndclass.hIcon = NULL;
- wndclass.hCursor = NULL;
- wndclass.hbrBackground = NULL;
- wndclass.lpszMenuName = NULL;
- wndclass.lpszClassName = VIM_CLASSNAME;
- RegisterClass(&wndclass);
-
- /* Create the message window. It will be hidden, so the details don't
- * matter. Don't use WS_OVERLAPPEDWINDOW, it will make a shortcut remove
- * focus from gvim. */
- message_window = CreateWindow(VIM_CLASSNAME, "",
- WS_POPUPWINDOW | WS_CAPTION,
- CW_USEDEFAULT, CW_USEDEFAULT,
- 100, 100, NULL, NULL,
- s_hinst, NULL);
-}
-
-/* Used by serverSendToVim() to find an alternate server name. */
-static char_u *altname_buf_ptr = NULL;
-
-/*
- * Get the title of the window "hwnd", which is the Vim server name, in
- * "name[namelen]" and return the length.
- * Returns zero if window "hwnd" is not a Vim server.
- */
- static int
-getVimServerName(HWND hwnd, char *name, int namelen)
-{
- int len;
- char buffer[VIM_CLASSNAME_LEN + 1];
-
- /* Ignore windows which aren't Vim message windows */
- len = GetClassName(hwnd, buffer, sizeof(buffer));
- if (len != VIM_CLASSNAME_LEN || STRCMP(buffer, VIM_CLASSNAME) != 0)
- return 0;
-
- /* Get the title of the window */
- return GetWindowText(hwnd, name, namelen);
-}
-
- static BOOL CALLBACK
-enumWindowsGetServer(HWND hwnd, LPARAM lparam)
-{
- struct server_id *id = (struct server_id *)lparam;
- char server[MAX_PATH];
-
- /* Get the title of the window */
- if (getVimServerName(hwnd, server, sizeof(server)) == 0)
- return TRUE;
-
- /* If this is the server we're looking for, return its HWND */
- if (STRICMP(server, id->name) == 0)
- {
- id->hwnd = hwnd;
- return FALSE;
- }
-
- /* If we are looking for an alternate server, remember this name. */
- if (altname_buf_ptr != NULL
- && STRNICMP(server, id->name, STRLEN(id->name)) == 0
- && vim_isdigit(server[STRLEN(id->name)]))
- {
- STRCPY(altname_buf_ptr, server);
- altname_buf_ptr = NULL; /* don't use another name */
- }
-
- /* Otherwise, keep looking */
- return TRUE;
-}
-
- static BOOL CALLBACK
-enumWindowsGetNames(HWND hwnd, LPARAM lparam)
-{
- garray_T *ga = (garray_T *)lparam;
- char server[MAX_PATH];
-
- /* Get the title of the window */
- if (getVimServerName(hwnd, server, sizeof(server)) == 0)
- return TRUE;
-
- /* Add the name to the list */
- ga_concat(ga, server);
- ga_concat(ga, "\n");
- return TRUE;
-}
-
- static HWND
-findServer(char_u *name)
-{
- struct server_id id;
-
- id.name = name;
- id.hwnd = 0;
-
- EnumWindows(enumWindowsGetServer, (LPARAM)(&id));
-
- return id.hwnd;
-}
-
- void
-serverSetName(char_u *name)
-{
- char_u *ok_name;
- HWND hwnd = 0;
- int i = 0;
- char_u *p;
-
- /* Leave enough space for a 9-digit suffix to ensure uniqueness! */
- ok_name = alloc((unsigned)STRLEN(name) + 10);
-
- STRCPY(ok_name, name);
- p = ok_name + STRLEN(name);
-
- for (;;)
- {
- /* This is inefficient - we're doing an EnumWindows loop for each
- * possible name. It would be better to grab all names in one go,
- * and scan the list each time...
- */
- hwnd = findServer(ok_name);
- if (hwnd == 0)
- break;
-
- ++i;
- if (i >= 1000)
- break;
-
- sprintf((char *)p, "%d", i);
- }
-
- if (hwnd != 0)
- vim_free(ok_name);
- else
- {
- /* Remember the name */
- serverName = ok_name;
-#ifdef FEAT_TITLE
- need_maketitle = TRUE; /* update Vim window title later */
-#endif
-
- /* Update the message window title */
- SetWindowText(message_window, ok_name);
-
-#ifdef FEAT_EVAL
- /* Set the servername variable */
- set_vim_var_string(VV_SEND_SERVER, serverName, -1);
-#endif
- }
-}
-
- char_u *
-serverGetVimNames(void)
-{
- garray_T ga;
-
- ga_init2(&ga, 1, 100);
-
- EnumWindows(enumWindowsGetNames, (LPARAM)(&ga));
- ga_append(&ga, NUL);
-
- return ga.ga_data;
-}
-
- int
-serverSendReply(name, reply)
- char_u *name; /* Where to send. */
- char_u *reply; /* What to send. */
-{
- HWND target;
- COPYDATASTRUCT data;
- long_u n = 0;
-
- /* The "name" argument is a magic cookie obtained from expand("<client>").
- * It should be of the form 0xXXXXX - i.e. a C hex literal, which is the
- * value of the client's message window HWND.
- */
- sscanf((char *)name, SCANF_HEX_LONG_U, &n);
- if (n == 0)
- return -1;
-
- target = (HWND)n;
- if (!IsWindow(target))
- return -1;
-
- data.dwData = COPYDATA_REPLY;
- data.cbData = (DWORD)STRLEN(reply) + 1;
- data.lpData = reply;
-
- serverSendEnc(target);
- if (SendMessage(target, WM_COPYDATA, (WPARAM)message_window,
- (LPARAM)(&data)))
- return 0;
-
- return -1;
-}
-
- int
-serverSendToVim(name, cmd, result, ptarget, asExpr, silent)
- char_u *name; /* Where to send. */
- char_u *cmd; /* What to send. */
- char_u **result; /* Result of eval'ed expression */
- void *ptarget; /* HWND of server */
- int asExpr; /* Expression or keys? */
- int silent; /* don't complain about no server */
-{
- HWND target;
- COPYDATASTRUCT data;
- char_u *retval = NULL;
- int retcode = 0;
- char_u altname_buf[MAX_PATH];
-
- /* If the server name does not end in a digit then we look for an
- * alternate name. e.g. when "name" is GVIM the we may find GVIM2. */
- if (STRLEN(name) > 1 && !vim_isdigit(name[STRLEN(name) - 1]))
- altname_buf_ptr = altname_buf;
- altname_buf[0] = NUL;
- target = findServer(name);
- altname_buf_ptr = NULL;
- if (target == 0 && altname_buf[0] != NUL)
- /* Use another server name we found. */
- target = findServer(altname_buf);
-
- if (target == 0)
- {
- if (!silent)
- EMSG2(_(e_noserver), name);
- return -1;
- }
-
- if (ptarget)
- *(HWND *)ptarget = target;
-
- data.dwData = asExpr ? COPYDATA_EXPR : COPYDATA_KEYS;
- data.cbData = (DWORD)STRLEN(cmd) + 1;
- data.lpData = cmd;
-
- serverSendEnc(target);
- if (SendMessage(target, WM_COPYDATA, (WPARAM)message_window,
- (LPARAM)(&data)) == 0)
- return -1;
-
- if (asExpr)
- retval = serverGetReply(target, &retcode, TRUE, TRUE);
-
- if (result == NULL)
- vim_free(retval);
- else
- *result = retval; /* Caller assumes responsibility for freeing */
-
- return retcode;
-}
-
-/*
- * Bring the server to the foreground.
- */
- void
-serverForeground(name)
- char_u *name;
-{
- HWND target = findServer(name);
-
- if (target != 0)
- SetForegroundWindow(target);
-}
-
-/* Replies from server need to be stored until the client picks them up via
- * remote_read(). So we maintain a list of server-id/reply pairs.
- * Note that there could be multiple replies from one server pending if the
- * client is slow picking them up.
- * We just store the replies in a simple list. When we remove an entry, we
- * move list entries down to fill the gap.
- * The server ID is simply the HWND.
- */
-typedef struct
-{
- HWND server; /* server window */
- char_u *reply; /* reply string */
- int expr_result; /* 0 for REPLY, 1 for RESULT 2 for error */
-} reply_T;
-
-static garray_T reply_list = {0, 0, sizeof(reply_T), 5, 0};
-
-#define REPLY_ITEM(i) ((reply_T *)(reply_list.ga_data) + (i))
-#define REPLY_COUNT (reply_list.ga_len)
-
-/* Flag which is used to wait for a reply */
-static int reply_received = 0;
-
-/*
- * Store a reply. "reply" must be allocated memory (or NULL).
- */
- static int
-save_reply(HWND server, char_u *reply, int expr)
-{
- reply_T *rep;
-
- if (ga_grow(&reply_list, 1) == FAIL)
- return FAIL;
-
- rep = REPLY_ITEM(REPLY_COUNT);
- rep->server = server;
- rep->reply = reply;
- rep->expr_result = expr;
- if (rep->reply == NULL)
- return FAIL;
-
- ++REPLY_COUNT;
- reply_received = 1;
- return OK;
-}
-
-/*
- * Get a reply from server "server".
- * When "expr_res" is non NULL, get the result of an expression, otherwise a
- * server2client() message.
- * When non NULL, point to return code. 0 => OK, -1 => ERROR
- * If "remove" is TRUE, consume the message, the caller must free it then.
- * if "wait" is TRUE block until a message arrives (or the server exits).
- */
- char_u *
-serverGetReply(HWND server, int *expr_res, int remove, int wait)
-{
- int i;
- char_u *reply;
- reply_T *rep;
-
- /* When waiting, loop until the message waiting for is received. */
- for (;;)
- {
- /* Reset this here, in case a message arrives while we are going
- * through the already received messages. */
- reply_received = 0;
-
- for (i = 0; i < REPLY_COUNT; ++i)
- {
- rep = REPLY_ITEM(i);
- if (rep->server == server
- && ((rep->expr_result != 0) == (expr_res != NULL)))
- {
- /* Save the values we've found for later */
- reply = rep->reply;
- if (expr_res != NULL)
- *expr_res = rep->expr_result == 1 ? 0 : -1;
-
- if (remove)
- {
- /* Move the rest of the list down to fill the gap */
- mch_memmove(rep, rep + 1,
- (REPLY_COUNT - i - 1) * sizeof(reply_T));
- --REPLY_COUNT;
- }
-
- /* Return the reply to the caller, who takes on responsibility
- * for freeing it if "remove" is TRUE. */
- return reply;
- }
- }
-
- /* If we got here, we didn't find a reply. Return immediately if the
- * "wait" parameter isn't set. */
- if (!wait)
- break;
-
- /* We need to wait for a reply. Enter a message loop until the
- * "reply_received" flag gets set. */
-
- /* Loop until we receive a reply */
- while (reply_received == 0)
- {
- /* Wait for a SendMessage() call to us. This could be the reply
- * we are waiting for. Use a timeout of a second, to catch the
- * situation that the server died unexpectedly. */
- MsgWaitForMultipleObjects(0, NULL, TRUE, 1000, QS_ALLINPUT);
-
- /* If the server has died, give up */
- if (!IsWindow(server))
- return NULL;
-
- serverProcessPendingMessages();
- }
- }
-
- return NULL;
-}
-
-/*
- * Process any messages in the Windows message queue.
- */
- void
-serverProcessPendingMessages(void)
-{
- MSG msg;
-
- while (pPeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
- {
- TranslateMessage(&msg);
- pDispatchMessage(&msg);
- }
-}
-
-#endif /* FEAT_CLIENTSERVER */
-
#if defined(FEAT_GUI) || (defined(FEAT_PRINTER) && !defined(FEAT_POSTSCRIPT)) \
|| defined(PROTO)
diff -r 15b934a16641 -r 2082fc32d223 src/os_unix.c
--- a/src/os_unix.c Wed Sep 14 19:04:40 2011 +0200
+++ b/src/os_unix.c Thu Sep 15 21:25:11 2011 +0900
@@ -378,6 +378,10 @@
netbeans_parse_messages();
#endif
+#if defined(FEAT_CLIENTSERVER)
+ cmdsrv_handle_requests();
+#endif
+
/* Check if window changed size while we were busy, perhaps the ":set
* columns=99" command was used. */
while (do_resize)
@@ -394,6 +398,9 @@
/* Process the queued netbeans messages. */
netbeans_parse_messages();
#endif
+#ifdef FEAT_CLIENTSERVER
+ cmdsrv_handle_requests();
+#endif
}
}
else /* wtime == -1 */
@@ -428,6 +435,9 @@
/* Process the queued netbeans messages. */
netbeans_parse_messages();
#endif
+#ifdef FEAT_CLIENTSERVER
+ cmdsrv_handle_requests();
+#endif
#ifndef VMS /* VMS: must try reading, WaitForChar() does nothing. */
/*
* We want to be interrupted by the winch signal
@@ -1540,10 +1550,6 @@
{
regmatch_T regmatch;
-#if defined(FEAT_CLIENTSERVER)
- if (x_force_connect)
- return TRUE;
-#endif
if (x_no_connect)
return FALSE;
@@ -3131,6 +3137,10 @@
netbeans_send_disconnect();
#endif
+#ifdef FEAT_CLIENTSERVER
+ cmdsrv_uninit();
+#endif
+
#ifdef EXITFREE
free_all_mem();
#endif
@@ -4864,6 +4874,9 @@
#ifdef FEAT_NETBEANS_INTG
int nb_fd = netbeans_filedesc();
#endif
+#ifdef FEAT_CLIENTSERVER
+ int cmdsrv_fd = cmdsrv_listenfd;
+#endif
#if defined(FEAT_XCLIPBOARD) || defined(USE_XSMP) || defined(FEAT_MZSCHEME)
static int busy = FALSE;
@@ -4913,7 +4926,7 @@
# endif
#endif
#ifndef HAVE_SELECT
- struct pollfd fds[6];
+ struct pollfd fds[7];
int nfd;
# ifdef FEAT_XCLIPBOARD
int xterm_idx = -1;
@@ -4927,6 +4940,9 @@
# ifdef FEAT_NETBEANS_INTG
int nb_idx = -1;
# endif
+# ifdef FEAT_CLIENTSERVER
+ int cmdsrv_idx = -1;
+# endif
int towait = (int)msec;
# ifdef FEAT_MZSCHEME
@@ -4986,6 +5002,15 @@
nfd++;
}
#endif
+#ifdef FEAT_CLIENTSERVER
+ if (cmdsrv_fd != -1)
+ {
+ cmdsrv_idx = nfd;
+ fds[nfd].fd = cmdsrv_fd;
+ fds[nfd].events = POLLIN;
+ nfd++;
+ }
+#endif
ret = poll(fds, nfd, towait);
# ifdef FEAT_MZSCHEME
@@ -5046,6 +5071,13 @@
--ret;
}
#endif
+# ifdef FEAT_CLIENTSERVER
+ if (ret > 0 && cmdsrv_idx != -1 && (fds[cmdsrv_idx].revents & POLLIN))
+ {
+ cmdsrv_handle_requests();
+ --ret;
+ }
+# endif
#else /* HAVE_SELECT */
@@ -5136,6 +5168,14 @@
maxfd = nb_fd;
}
#endif
+# ifdef FEAT_CLIENTSERVER
+ if (cmdsrv_fd != -1)
+ {
+ FD_SET(cmdsrv_fd, &rfds);
+ if (maxfd < cmdsrv_fd)
+ maxfd = cmdsrv_fd;
+ }
+# endif
# ifdef OLD_VMS
/* Old VMS as v6.2 and older have broken select(). It waits more than
@@ -5228,6 +5268,13 @@
--ret;
}
#endif
+# ifdef FEAT_CLIENTSERVER
+ if (ret > 0 && cmdsrv_fd != -1 && FD_ISSET(cmdsrv_fd, &rfds))
+ {
+ cmdsrv_handle_requests();
+ --ret;
+ }
+# endif
#endif /* HAVE_SELECT */
@@ -6725,15 +6772,6 @@
while (XtAppPending(app_context) && !vim_is_input_buf_full())
{
XtAppNextEvent(app_context, &event);
-#ifdef FEAT_CLIENTSERVER
- {
- XPropertyEvent *e = (XPropertyEvent *)&event;
-
- if (e->type == PropertyNotify && e->window == commWindow
- && e->atom == commProperty && e->state == PropertyNewValue)
- serverEventProc(xterm_dpy, &event);
- }
-#endif
XtDispatchEvent(&event);
}
}
diff -r 15b934a16641 -r 2082fc32d223 src/os_win32.c
--- a/src/os_win32.c Wed Sep 14 19:04:40 2011 +0200
+++ b/src/os_win32.c Thu Sep 15 21:25:11 2011 +0900
@@ -1205,7 +1205,7 @@
mzvim_check_threads();
#endif
#ifdef FEAT_CLIENTSERVER
- serverProcessPendingMessages();
+ cmdsrv_handle_requests();
#endif
if (0
#ifdef FEAT_MOUSE
@@ -1227,21 +1227,39 @@
if (msec != 0)
{
DWORD dwWaitTime = dwEndTime - dwNow;
+ DWORD dwWait;
+ int nitems = 0;
+#ifdef FEAT_CLIENTSERVER
+ HANDLE hObjects[1 + CMDSRV_INSTANCES];
+#else
+ HANDLE hObjects[1];
+#endif
+
+ hObjects[nitems++] = g_hConIn;
+
+#ifdef FEAT_CLIENTSERVER
+ if (cmdsrv_events != NULL)
+ {
+ mch_memmove(hObjects + nitems, cmdsrv_events,
+ sizeof(HANDLE) * CMDSRV_INSTANCES);
+ nitems += CMDSRV_INSTANCES;
+ }
+#endif
#ifdef FEAT_MZSCHEME
if (mzthreads_allowed() && p_mzq > 0
&& (msec < 0 || (long)dwWaitTime > p_mzq))
dwWaitTime = p_mzq; /* don't wait longer than 'mzquantum' */
#endif
-#ifdef FEAT_CLIENTSERVER
- /* Wait for either an event on the console input or a message in
- * the client-server window. */
- if (MsgWaitForMultipleObjects(1, &g_hConIn, FALSE,
- dwWaitTime, QS_SENDMESSAGE) != WAIT_OBJECT_0)
-#else
- if (WaitForSingleObject(g_hConIn, dwWaitTime) != WAIT_OBJECT_0)
-#endif
- continue;
+
+ dwWait = WaitForMultipleObjects(nitems, hObjects, FALSE, dwWaitTime);
+ if (dwWait == WAIT_FAILED)
+ break;
+ else if (dwWait == WAIT_TIMEOUT)
+ break;
+ else if (dwWait != WAIT_OBJECT_0)
+ /* Signaled object is not g_hConIn. */
+ continue;
}
cRecords = 0;
@@ -2282,6 +2300,10 @@
ml_close_all(TRUE); /* remove all memfiles */
+#ifdef FEAT_CLIENTSERVER
+ cmdsrv_uninit();
+#endif
+
if (g_fWindInitCalled)
{
#ifdef FEAT_TITLE
diff -r 15b934a16641 -r 2082fc32d223 src/proto.h
--- a/src/proto.h Wed Sep 14 19:04:40 2011 +0200
+++ b/src/proto.h Thu Sep 15 21:25:11 2011 +0900
@@ -253,8 +253,9 @@
# ifdef FEAT_OLE
# include "if_ole.pro"
# endif
-# if defined(FEAT_CLIENTSERVER) && defined(FEAT_X11)
-# include "if_xcmdsrv.pro"
+
+# ifdef FEAT_CLIENTSERVER
+# include "if_cmdsrv.pro"
# endif
/*
diff -r 15b934a16641 -r 2082fc32d223 src/proto/if_cmdsrv.pro
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/proto/if_cmdsrv.pro Thu Sep 15 21:25:11 2011 +0900
@@ -0,0 +1,20 @@
+/* if_cmdsrv.c */
+int cmdsrv_init __ARGS((void));
+int cmdsrv_uninit __ARGS((void));
+int cmdsrv_gui_register __ARGS((void));
+int cmdsrv_gui_unregister __ARGS((void));
+int cmdsrv_register_name __ARGS((char_u *name));
+int cmdsrv_server_list __ARGS((char_u **result));
+int cmdsrv_wait_request __ARGS((int timeoutmsec));
+int cmdsrv_handle_requests __ARGS((void));
+int cmdsrv_send_keys __ARGS((char_u *serverid, char_u *keys));
+int cmdsrv_send_expr __ARGS((char_u *serverid, char_u *expr, char_u **result));
+int cmdsrv_send_notification __ARGS((char_u *serverid, char_u *reply));
+int cmdsrv_foreground __ARGS((char_u *serverid));
+int cmdsrv_peek_reply __ARGS((char_u *serverid, char_u **pstr));
+int cmdsrv_read_reply __ARGS((char_u *serverid, char_u **pstr));
+int cmdsrv_wait_reply __ARGS((char_u *serverid, char_u **pstr));
+char_u *cmdsrv_find_server __ARGS((char_u *name, int loose));
+char_u *cmdsrv_urlencode(char_u *str);
+char_u *cmdsrv_urldecode(char_u *str);
+/* vim: set ft=c : */
diff -r 15b934a16641 -r 2082fc32d223 src/proto/if_xcmdsrv.pro
--- a/src/proto/if_xcmdsrv.pro Wed Sep 14 19:04:40 2011 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,11 +0,0 @@
-/* if_xcmdsrv.c */
-int serverRegisterName __ARGS((Display *dpy, char_u *name));
-void serverChangeRegisteredWindow __ARGS((Display *dpy, Window newwin));
-int serverSendToVim __ARGS((Display *dpy, char_u *name, char_u *cmd, char_u **result, Window *server, int asExpr, int localLoop, int silent));
-char_u *serverGetVimNames __ARGS((Display *dpy));
-Window serverStrToWin __ARGS((char_u *str));
-int serverSendReply __ARGS((char_u *name, char_u *str));
-int serverReadReply __ARGS((Display *dpy, Window win, char_u **str, int localLoop));
-int serverPeekReply __ARGS((Display *dpy, Window win, char_u **str));
-void serverEventProc __ARGS((Display *dpy, XEvent *eventPtr));
-/* vim: set ft=c : */
diff -r 15b934a16641 -r 2082fc32d223 src/proto/os_mswin.pro
--- a/src/proto/os_mswin.pro Wed Sep 14 19:04:40 2011 +0200
+++ b/src/proto/os_mswin.pro Thu Sep 15 21:25:11 2011 +0900
@@ -50,14 +50,6 @@
void mch_print_set_fg __ARGS((long_u fgcol));
char_u *mch_resolve_shortcut __ARGS((char_u *fname));
void win32_set_foreground __ARGS((void));
-void serverInitMessaging __ARGS((void));
-void serverSetName __ARGS((char_u *name));
-char_u *serverGetVimNames __ARGS((void));
-int serverSendReply __ARGS((char_u *name, char_u *reply));
-int serverSendToVim __ARGS((char_u *name, char_u *cmd, char_u **result, void *ptarget, int asExpr, int silent));
-void serverForeground __ARGS((char_u *name));
-char_u *serverGetReply __ARGS((HWND server, int *expr_res, int remove, int wait));
-void serverProcessPendingMessages __ARGS((void));
char *charset_id2name __ARGS((int id));
int get_logfont __ARGS((LOGFONT *lf, char_u *name, HDC printer_dc, int verbose));
/* vim: set ft=c : */
diff -r 15b934a16641 -r 2082fc32d223 src/testdir/cmdsrv-test.vim
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/testdir/cmdsrv-test.vim Thu Sep 15 21:25:11 2011 +0900
@@ -0,0 +1,390 @@
+#!vim -u
+" Test for cmdsrv-nox.
+" Run this script in src directory as ./vim -u testdir/cmdsrv-test.vim.
+" This script works under GNOME desktop or Windows desktop.
+
+if has('vim_starting')
+ set nocompatible
+ set loadplugins
+ call feedkeys(":source " . expand('<sfile>') . "\<CR>")
+ finish
+endif
+
+set nocompatible
+set nomore
+
+function! Sleep(n)
+ execute 'sleep' a:n
+endfunction
+
+function! WaitResponse(serverid)
+ if has('win32')
+ " WORKAROUND: update event loop to receive response
+ sleep 1
+ call remote_expr(a:serverid, 'remote_expr("' . v:servername . '", "Sleep(1)")')
+ else
+ sleep 1
+ endif
+endfunction
+
+function! s:serverlist()
+ return split(serverlist(), '\n')
+endfunction
+
+function! s:cui_start_server(name)
+ let nservers = len(s:serverlist())
+ if has('win32')
+ let cmd = printf('start .\vim.exe -u NORC --servername %s', shellescape(a:name, 1))
+ silent! execute '!' . cmd
+ else
+ let cmd = printf("gnome-terminal -e \"./vim -u NORC --servername %s\"", escape(shellescape(a:name), '\"'))
+ call system(cmd)
+ endif
+ if v:shell_error
+ throw 'cui_start_server: failed to start server'
+ endif
+ " wait server ready
+ for i in range(100)
+ if nservers != len(s:serverlist())
+ return
+ endif
+ sleep 100m
+ endfor
+ throw 'cui_start_server: failed to start server'
+endfunction
+
+function! s:gui_start_server(name)
+ let nservers = len(s:serverlist())
+ if has('win32')
+ let cmd = printf('start .\gvim.exe -u NORC --servername %s', shellescape(a:name, 1))
+ silent! execute '!' . cmd
+ else
+ let cmd = printf('./vim -g -u NORC --servername %s', shellescape(a:name))
+ call system(cmd)
+ endif
+ if v:shell_error
+ throw 'gui_start_server: failed to start server'
+ endif
+ " wait server ready
+ for i in range(100)
+ if nservers != len(s:serverlist())
+ return
+ endif
+ sleep 100m
+ endfor
+ throw 'gui_start_server: failed to start server'
+endfunction
+
+let s:servermode = 'cui'
+
+function! s:start_server(name)
+ if s:servermode == 'cui'
+ call s:cui_start_server(a:name)
+ else
+ call s:gui_start_server(a:name)
+ endif
+endfunction
+
+function! s:close_server(name)
+ let nservers = len(s:serverlist())
+ call remote_send(a:name, '<C-\><C-N>:qall!<CR>')
+ " wait server closed
+ for i in range(100)
+ if nservers != len(s:serverlist())
+ return
+ endif
+ sleep 100m
+ endfor
+ throw 'close_server: failed to close server'
+endfunction
+
+function! s:close_all_servers()
+ for name in s:serverlist()
+ if name =~? '^\(ONE\|TWO\|THREE\)\d*$'
+ call s:close_server(name)
+ endif
+ endfor
+endfunction
+
+function! s:test_loosename1()
+ echomsg 'test_loosename1: Test for loosename'
+ call s:start_server('one')
+ call s:start_server('one')
+ call s:start_server('one')
+ let servers = s:serverlist()
+ if index(servers, 'one', 0, 1) == -1 || index(servers, 'one1', 0, 1) == -1
+ \ || index(servers, 'one2', 0, 1) == -1
+ throw 'test_loosename1: failed'
+ endif
+ call s:close_all_servers()
+endfunction
+
+function! s:test_loosename2()
+ echomsg 'test_loosename2: Test for loosename.'
+ " one1 already used, second server will be named as one11.
+ call s:start_server('one1')
+ call s:start_server('one1')
+ let servers = s:serverlist()
+ if index(servers, 'one1', 0, 1) == -1 || index(servers, 'one11', 0, 1) == -1
+ throw 'test_loosename2: failed'
+ endif
+ call s:close_all_servers()
+endfunction
+
+function! s:test_loosename3()
+ echomsg 'test_loosename3: Test for many instances.'
+ let n = 20
+ for i in range(n)
+ let name = printf('one%d', i)
+ call s:start_server(name)
+ endfor
+ for i in range(n)
+ let name = printf('one%d', i)
+ if remote_expr(name, 'v:servername') !=? name
+ throw 'test_loosename3: failed'
+ endif
+ endfor
+ call s:close_all_servers()
+endfunction
+
+function! s:test_loosename4()
+ echomsg 'test_loosename4: Test for special character which is not safe in file name'
+ let servername = '/\*"[]:;|=?'
+ call s:start_server(servername)
+ if index(s:serverlist(), servername) == -1
+ throw 'test_loosename4: failed'
+ endif
+ call s:close_server(servername)
+endfunction
+
+function! s:test_remote_send1()
+ echomsg 'test_remote_send1: Test for remote_send().'
+ call s:start_server('one')
+ call remote_send('one', 'ihello<Esc>')
+ call WaitResponse('one')
+ let result = remote_expr('one', 'getline(1)')
+ if result !=# 'hello'
+ throw 'test_remote_send1: failed'
+ endif
+ call s:close_all_servers()
+endfunction
+
+function! s:test_remote_expr1()
+ echomsg 'test_remote_expr1: Test for remote_expr().'
+ call s:start_server('one')
+ let result = remote_expr('one', 'v:servername')
+ if result !=# 'ONE'
+ throw 'test_remote_expr1: failed'
+ endif
+ call s:close_all_servers()
+endfunction
+
+function! s:test_remote_expr2()
+ echomsg 'test_remote_expr2: Test for remote_expr().'
+ call s:start_server('one')
+ for i in range(100)
+ let result = remote_expr('one', i)
+ if result != i
+ throw 'test_remote_expr2: failed'
+ endif
+ endfor
+ call s:close_all_servers()
+endfunction
+
+let s:test_remote_expr3_count = 0
+
+function! _test_remote_expr3_recursive(serverid, n)
+ if a:n == 0
+ return v:servername
+ endif
+ let s:test_remote_expr3_count += 1
+ return v:servername . remote_expr(a:serverid, 'v:servername . remote_expr("' . v:servername . '", "_test_remote_expr3_recursive(\"" . v:servername . "\", ' . (a:n - 1) . ')")')
+endfunction
+
+function! s:test_remote_expr3()
+ echomsg 'test_remote_expr3: Test for recursive call.'
+ call s:start_server('one')
+ let s:test_remote_expr3_count = 0
+ let result = _test_remote_expr3_recursive('one', 3)
+ let expect = join(repeat([v:servername], 4), 'ONE')
+ if s:test_remote_expr3_count != 3 || result != expect
+ throw 'test_remote_expr3: failed'
+ endif
+ call s:close_all_servers()
+endfunction
+
+function! s:test_reply1()
+ echomsg 'test_reply1: Test for remote_peek().'
+ call s:start_server('one')
+ let cmd = '<C-\><C-N>:call server2client(expand("<client>"), "hello")<CR>'
+ call remote_send('one', cmd, 'serverid')
+ call WaitResponse('one')
+ let available = remote_peek(serverid, 'result')
+ if !available || result !=# 'hello'
+ throw 'test_reply1: failed'
+ endif
+ " clear
+ while remote_peek(serverid)
+ call remote_read(serverid)
+ endwhile
+ call s:close_all_servers()
+endfunction
+
+function! s:test_reply2()
+ echomsg 'test_reply2: Test for remote_read().'
+ call s:start_server('one')
+ let cmd = '<C-\><C-N>:call server2client(expand("<client>"), "hello")<CR>'
+ call remote_send('one', cmd, 'serverid')
+ call WaitResponse('one')
+ let result = remote_read(serverid)
+ if result !=# 'hello'
+ throw 'test_reply2: failed'
+ endif
+ " clear
+ while remote_peek(serverid)
+ call remote_read(serverid)
+ endwhile
+ call s:close_all_servers()
+endfunction
+
+function! s:test_reply3()
+ echomsg 'test_reply3: Test for remote_read() with remote_expr.'
+ call s:start_server('one')
+ let cmd = 'server2client(expand("<client>"), "hello")'
+ call remote_expr('one', cmd, 'serverid')
+ call WaitResponse('one')
+ let result = remote_read(serverid)
+ if result !=# 'hello'
+ throw 'test_reply3: failed'
+ endif
+ " clear
+ while remote_peek(serverid)
+ call remote_read(serverid)
+ endwhile
+ call s:close_all_servers()
+endfunction
+
+function! s:test_reply4()
+ echomsg 'test_reply4: Test for RemoteReply autocommand.'
+ let s:test_reply4_result = 'deadbeaf'
+ call s:start_server('one')
+ let cmd = '<C-\><C-N>:call server2client(expand("<client>"), "hello")<CR>'
+ call remote_send('one', cmd, 'serverid')
+ augroup TestReply4
+ au!
+ execute printf("autocmd RemoteReply %s let s:test_reply4_result = expand('<afile>')", serverid)
+ augroup END
+ call WaitResponse('one')
+ if s:test_reply4_result !=# 'hello'
+ throw 'test_reply4: failed'
+ endif
+ " clear
+ while remote_peek(serverid)
+ call remote_read(serverid)
+ endwhile
+ call s:close_all_servers()
+ augroup TestReply4
+ au!
+ augroup END
+endfunction
+
+function! s:test_reply5()
+ echomsg 'test_reply5: Test for remote_read with sleep'
+ call s:start_server('one')
+ let cmd = '<C-\><C-N>:sleep 2 | call server2client(expand("<client>"), "hello")<CR>'
+ call remote_send('one', cmd, 'serverid')
+ let result = remote_read(serverid)
+ if result !=# 'hello'
+ throw 'test_reply5: failed'
+ endif
+ " clear
+ while remote_peek(serverid)
+ call remote_read(serverid)
+ endwhile
+ call s:close_all_servers()
+endfunction
+
+function! s:test_error1()
+ echomsg 'test_error1: Test for non-existence serverid'
+ let ok = 0
+ try
+ call remote_expr('nonexistence', '0')
+ catch /^Vim\%((\a\+)\)\=:E241:/
+ " E241: Unable to send to %s
+ let ok = 1
+ endtry
+ if !ok
+ throw 'test_error1: failed'
+ endif
+endfunction
+
+function! s:test_error2()
+ echomsg 'test_error2: Test for invalid expression'
+ call s:start_server('one')
+ let ok = 0
+ try
+ call remote_expr('one', 'invalid expression')
+ catch /^Vim\%((\a\+)\)\=:E449:/
+ " E449: Invalid expression received
+ let ok = 1
+ endtry
+ if !ok
+ throw 'test_error2: failed'
+ endif
+ call s:close_all_servers()
+endfunction
+
+function! s:test_error3()
+ echomsg 'test_error3: Test for exception'
+ call s:start_server('one')
+ call remote_send('one', '<C-\><C-N>:function Raise()<CR>throw "Raise()"<CR>endfunction<CR><CR>')
+ sleep 1
+ let result = remote_expr('one', 'Raise()')
+ if result !=# '0'
+ throw 'test_error3: failed'
+ endif
+ call s:close_all_servers()
+endfunction
+
+function! s:test_error4()
+ echomsg 'test_error4: Test for remote_read() with non-existence serverid'
+ let ok = 0
+ try
+ call remote_read('0xffffffff')
+ catch /^Vim\%((\a\+)\)\=:E277:/
+ " E277: Unable to read a server reply
+ let ok = 1
+ endtry
+ if !ok
+ throw 'test_error4: failed'
+ endif
+endfunction
+
+function! s:main()
+ for servermode in ['cui', 'gui']
+ let s:servermode = servermode
+ call s:test_loosename1()
+ call s:test_loosename2()
+ call s:test_loosename3()
+ call s:test_loosename4()
+ call s:test_remote_send1()
+ call s:test_remote_expr1()
+ call s:test_remote_expr2()
+ call s:test_remote_expr3()
+ call s:test_reply1()
+ call s:test_reply2()
+ call s:test_reply3()
+ call s:test_reply4()
+ call s:test_reply5()
+ call s:test_error1()
+ call s:test_error2()
+ call s:test_error3()
+ call s:test_error4()
+ endfor
+ echomsg "all test done"
+endfunction
+
+try
+ call s:main()
+endtry
+
@karino2
Copy link

karino2 commented Sep 21, 2016

このパッチを当てたvimが欲しくなった為、本家のvimをforkして当ててみました。

https://github.com/karino2/vim/tree/cmdsrv-nox

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment