Re: How can I open file in exist window?

Fabrice Popineau <[email protected]>
Newsgroups gmane.emacs.xemacs.windows,gmane.emacs.xemacs.beta
Message-ID <[email protected]>
> I'd like that starting XEmacs-NT [version 21.4; April 2001] as xemacs
> +100 foo.tex

> should open foo.txt at line 100 with launched instance of XEmacs,
> rather than start another one.

> The program `winclient.exe' does not meet my needs, becase it does not
> recognize the option `+number-line'.

Juste because the most recent work from Alastair J. Houghton has not
been integrated into the main source tree.

Try the files attached. It will work the way you want.

-- 
Fabrice
winclient.c (application/octet-stream, 9.2 KB)
/* DDE client for XEmacs.
   Copyright (C) 2002 Alastair J. Houghton

   This file is part of XEmacs.

   XEmacs is free software; you can redistribute it and/or modify it
   under the terms of the GNU General Public License as published by the
   Free Software Foundation; either version 2, or (at your option) any
   later version.

   XEmacs is distributed in the hope that it will be useful, but WITHOUT
   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   for more details.

   You should have received a copy of the GNU General Public License
   along with XEmacs; see the file COPYING.  If not, write to
   the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
   Boston, MA 02111-1307, USA.  */

/* Synched up with: Not in FSF. */

#include <windows.h>
#include <ddeml.h>
#include <dde.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>

#define XEMACS_EXE	"xemacs.exe"
#define XEMACS		"XEmacs"
#define EVAL_TOPIC	"Eval"
#define RESULT_ITEM	"Result"
#define ERROR_ITEM	"Error"

/* Timeouts & delays */
#define CONNECT_DELAY		500		/* ms */
#define TRANSACTION_TIMEOUT	5000		/* ms */
#define MAX_INPUT_IDLE_WAIT     INFINITE	/* ms */

static DWORD DDEsession;
static HCONV DDEconversation;

void CloseConversation (void)
{
    if (DDEconversation)
	DdeDisconnect(DDEconversation);
    if (DDEsession)
	DdeUninitialize(DDEsession);
}

void error(LPCTSTR fmt, ...)
{
    va_list ap;
    va_start(ap, fmt);
    vfprintf(stderr, fmt, ap);
    va_end(ap);
    fputc('\n', stderr);

    /* Tidy up */
    CloseConversation();
    exit(1);
}

void *emalloc(size_t len)
{
    void *p = malloc(len);

    if (p == NULL)
	error("Out of memory - cannot allocate %d bytes", len);

    return p;
}

int outstanding_requests;

HDDEDATA CALLBACK
Callback (UINT uType, UINT uFmt, HCONV hconv, HSZ hsz1, HSZ hsz2,
	  HDDEDATA hdata, DWORD dwData1, DWORD dwData2)
{
#ifndef WINDOIT
    if (uType == XTYP_ADVDATA)
    {
	DWORD len = DdeGetData(hdata, NULL, 0, 0);
	char *buf = _alloca(len + 1);
	DdeGetData(hdata, (LPBYTE)buf, len + 1, 0);

	if (--outstanding_requests == 0)
	    PostQuitMessage(0);

	return (HDDEDATA) DDE_FACK;
    }
#endif
    return (HDDEDATA) NULL;
}

int StartServer(LPCTSTR prog)
{
    STARTUPINFO si;
    PROCESS_INFORMATION pi;
    int n;

    ZeroMemory (&si, sizeof (si));
    si.cb = sizeof (si);
    if (!CreateProcess (NULL, (LPTSTR)prog, NULL, NULL, FALSE, 0,
			NULL, NULL, &si, &pi))
    {
	error("Could not start process %s", prog);
	return 1;
    }

    /* Wait for the process to enter an idle state */
    WaitForInputIdle (pi.hProcess, MAX_INPUT_IDLE_WAIT);

    /* Close the handles */
    CloseHandle (pi.hThread);
    CloseHandle (pi.hProcess);
    return 0;
}

HSZ DDEString(LPCTSTR str)
{
    HSZ hsz = DdeCreateStringHandle(DDEsession, str, CP_WINANSI);
    if (hsz == 0)
	error("Cannot create string for %s", str);
    return hsz;
}

FreeString(HSZ hsz)
{
    DdeFreeStringHandle(DDEsession, hsz);
}

void OpenConversation(LPCTSTR topic_name)
{
    UINT ret;
    HSZ service;
    HSZ topic;
    int n;
    
    ret = DdeInitialize(&DDEsession, Callback, APPCMD_CLIENTONLY, 0);
    if (ret != DMLERR_NO_ERROR)
	error("Cannot start DDE");

    service = DDEString(XEMACS);
    topic = DDEString(topic_name);
    DDEconversation = DdeConnect(DDEsession, service, topic, 0);

    if (DDEconversation == 0)
    {
	if (StartServer(XEMACS_EXE) == 0)
	{
	    /* Try to connect */
	    for (n = 0; n < 5; n++)
	    {
		Sleep (CONNECT_DELAY);
		DDEconversation = DdeConnect(DDEsession, service, topic, 0);
		if (DDEconversation)
		    break;
	    }
	    if (DDEconversation == 0)
		error("Cannot contact server %s", XEMACS);
	}
    }
    FreeString(service);
    FreeString(topic);
}

void ExecuteCommand(LPCTSTR command)
{
    HDDEDATA ret;
    ret = DdeClientTransaction((LPBYTE)command, strlen(command) + 1,
			       DDEconversation, 0, 0, XTYP_EXECUTE,
			       TRANSACTION_TIMEOUT, 0);
    if (ret == 0)
	error("Cannot execute command \"%s\"", command);
}

void StartHotLink(LPCTSTR item_name)
{
    HSZ item = DDEString(item_name);
    DdeClientTransaction(0, 0, DDEconversation, item, CF_TEXT, XTYP_ADVSTART,
			 TRANSACTION_TIMEOUT, 0);
    FreeString(item);
}

LPTSTR RequestData (LPCTSTR item_name)
{
    HSZ item = DDEString(item_name);
    DWORD len;
    char *buf;
    HDDEDATA result;
    result = DdeClientTransaction (NULL, 0, DDEconversation, item, CF_TEXT,
				   XTYP_REQUEST, TRANSACTION_TIMEOUT, 0);
    FreeString(item);
    if (result == 0)
	error("Cannot request item %s\n", item_name);

    len = DdeGetData(result, NULL, 0, 0);
    buf = emalloc(len + 1);
    DdeGetData(result, (LPBYTE)buf, len + 1, 0);
    return buf;
}

void pump_messages()
{
    MSG msg;
    HWND hwnd;
    BOOL ret;

    while ((ret = GetMessage(&msg, NULL, 0, 0)) != 0)
    {
	if (ret != -1)
	{
	    TranslateMessage(&msg);
	    DispatchMessage(&msg);
	}
    }
}

LPCTSTR EvaluateCommand(LPCTSTR forms)
{
    int i;
    LPTSTR result;
    ExecuteCommand(forms);
    result = RequestData(RESULT_ITEM);

    /* Status is "OK: xxx" or "ERR: xxx" */
    if (strncmp(result, "ERR:", 4) == 0)
	error("%s\n", result + 5);

    /* Move the result down */
    for (i = 4; result[i]; ++i)
	result[i-4] = result[i];
    result[i-4] = 0;
    return result;
}

LPCTSTR BuildForm(LPCTSTR command, LPCTSTR path)
{
    /* Format is (command "path"), where backslashes and quotes in path
     * must be backslash-escaped. So we need a buffer of size command length
     * plus 2 * path length plus 6 (quotes, parens, space, and terminating 0).
     */
    size_t buflen = strlen(command) + 2 * strlen(path) + 6;
    LPTSTR buf = emalloc(buflen);
    LPCTSTR src;
    LPTSTR dest = buf;

    *dest++ = '(';
    strcpy(dest, command);
    dest += strlen(command);
    *dest++ = ' ';
    *dest++ = '"';

    for (src = path; *src; ++src)
    {
	if (*src == '\\' || *src == '"')
	    *dest++ = '\\';
	*dest++ = *src;
    }

    *dest++ = '"';
    *dest++ = ')';
    *dest = 0;

    return buf;
}

void LoadFile(LPCTSTR command, LPCTSTR file, int line, LPCTSTR *result)
{
    LPTSTR filepart;
    LPCTSTR form;
    TCHAR path[MAX_PATH];

    if (GetFullPathName(file, MAX_PATH, path, &filepart) == 0)
	error("Cannot get path for %s", file);

    form = BuildForm(command, path);
    if (result)
	*result = EvaluateCommand(form);
    else
	ExecuteCommand(form);
    free((void *)form);

    if (line >= 0)
    {
	char buf[50];
	sprintf(buf, "(goto-line %d)", line);
	ExecuteCommand(buf);
    }
}

void do_files (int argc, LPCTSTR argv[], int wait)
{
    int i;
    LPCTSTR cmd;
    LPCTSTR result;

    OpenConversation(EVAL_TOPIC);
    if (wait)
    {
        cmd = "request-edit";
        ExecuteCommand("(require 'dde)");
	outstanding_requests = 0;
    }
    else
    {
	cmd = "find-file";
    }

    for (; argc; ++argv, --argc)
    {
	int line = -1;

	if (argc > 1 && *argv[0] == '+')
	{
	    line = atoi(argv[0]);
	    ++argv;
	    --argc;
	}

	LoadFile(cmd, *argv, line, (wait ? &result : 0));
        ExecuteCommand("(raise-frame)");
	if (wait)
	{
	    ++outstanding_requests;
	    StartHotLink(result);
	    free((void *)result);
	}
    }

    if (wait)
    {
	/* Wait for completion notifications... */
	pump_messages();
    }

    CloseConversation();
}

void usage()
{
    printf("Usage:\n");
#ifdef WINDOIT
    printf("windoit [-q] form...\n");
    printf("    Evaluate forms (-q means do not wait for a result)\n");
#else
    printf("winclient [-w] file...\n");
    printf("    Load files (-w means wait for the user to finish)\n");
#endif
}

#ifdef WINDOIT
void SkipProgramName (LPTSTR *cmdline)
{
    int in_quote = 0;
    LPTSTR cmd = *cmdline;

    while (*cmd)
    {
	if (!in_quote && isspace(*cmd))
	    break;

	if (*cmd == '"')
	    in_quote = !in_quote;

	/* Backslash protects quotes
	 * so they don't count for protecting spaces
	 */
	if (*cmd == '\\')
	    ++cmd;

	++cmd;
    }

    while (*cmd && isspace(*cmd))
	++cmd;

    *cmdline = cmd;
}

void TrimTrailingSpace (LPTSTR cmdline)
{
    size_t len = strlen(cmdline);

    while (len > 0 && isspace(cmdline[len-1]))
	--len;

    cmdline[len] = '\0';
}

int CheckOption(LPTSTR *cmdline, TCHAR option)
{
    LPTSTR cmd = *cmdline;
    if (cmd[0] == '-' && cmd[1] == option
	&& (cmd[2] == '\0' || isspace(cmd[2])))
    {
	cmd += 2;
	while (*cmd && isspace(*cmd))
	    ++cmd;
	*cmdline = cmd;
	return 1;
    }

    return 0;
}

int main ()
{
    LPTSTR cmdline = GetCommandLine();
    int quiet = 0;

    SkipProgramName(&cmdline);
    TrimTrailingSpace(cmdline);

    if (*cmdline == 0 || CheckOption(&cmdline, '?'))
    {
	usage();
	return 0;
    }

    if (CheckOption(&cmdline, 'q'))
	quiet = 1;

    OpenConversation(EVAL_TOPIC);
    if (quiet)
	ExecuteCommand(cmdline);
    else
    {
	LPCTSTR result = EvaluateCommand(cmdline);
	printf("%s\n", result);
	free((void *)result);
    }
    CloseConversation();
    return 0;
}
#else
int main (int argc, const char *argv[])
{
    int i;
    int wait = 0;

    /* Skip the program name */
    ++argv;
    --argc;

    if (argc == 0 || strcmp(argv[0], "-?") == 0)
    {
	usage();
	return 0;
    }

    if (strcmp(argv[0], "-w") == 0)
    {
	wait = 1;
	++argv;
	--argc;
    }

    do_files(argc, argv, wait);
    return 0;
}
#endif
dde.el (application/emacs-lisp, 440 B) - not displayed
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.