-/* DDE client for XEmacs.\r
- Copyright (C) 2002 Alastair J. Houghton\r
-\r
- This file is part of XEmacs.\r
-\r
- XEmacs is free software; you can redistribute it and/or modify it\r
- under the terms of the GNU General Public License as published by the\r
- Free Software Foundation; either version 2, or (at your option) any\r
- later version.\r
-\r
- XEmacs is distributed in the hope that it will be useful, but WITHOUT\r
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\r
- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License\r
- for more details.\r
-\r
- You should have received a copy of the GNU General Public License\r
- along with XEmacs; see the file COPYING. If not, write to\r
- the Free Software Foundation, Inc., 59 Temple Place - Suite 330,\r
- Boston, MA 02111-1307, USA. */\r
-\r
-/* Synched up with: Not in FSF. */\r
-\r
-/* -- Pre-Include Defines --------------------------------------------------- */\r
-\r
-#define STRICT\r
-\r
-/* -- Includes -------------------------------------------------------------- */\r
-\r
-#include <windows.h>\r
-#ifdef HAVE_CONFIG_H\r
-# include <config.h>\r
-#endif\r
-#include <stdlib.h>\r
-#include <stdio.h>\r
-#include <ctype.h>\r
-#include <errno.h>\r
-\r
-static void error (const char* s1, const char* s2);\r
-static void fatal (const char *s1, const char *s2);\r
-static void * xmalloc (size_t size);\r
-static char * getNextArg (const char **ptr, unsigned *len);\r
-\r
-/* -- Post-Include Defines -------------------------------------------------- */\r
-\r
-/* Timeouts & delays */\r
-#define CONNECT_DELAY 500 /* ms */\r
-#define TRANSACTION_TIMEOUT 5000 /* ms */\r
-#define MAX_INPUT_IDLE_WAIT INFINITE /* ms */\r
-\r
-/* DDE Strings */\r
-#define SERVICE_NAME "XEmacs"\r
-#define TOPIC_NAME "System"\r
-#define COMMAND_FORMAT "[open(\"%s%s\")]"\r
-\r
-/* XEmacs program name */\r
-#define PROGRAM_TO_RUN "xemacs.exe"\r
-\r
-/* -- Constants ------------------------------------------------------------- */\r
-\r
-/* -- Global Variables ------------------------------------------------------ */\r
-\r
-HINSTANCE hInstance;\r
-DWORD idInst = 0;\r
-\r
-/* -- Function Declarations ------------------------------------------------- */\r
-\r
-HDDEDATA CALLBACK ddeCallback (UINT uType, UINT uFmt, HCONV hconv,\r
- HSZ hsz1, HSZ hsz2, HDDEDATA hdata,\r
- DWORD dwData1, DWORD dwData2);\r
-\r
-int WINAPI WinMain (HINSTANCE hInst,\r
- HINSTANCE hPrev,\r
- LPSTR lpCmdLine,\r
- int nCmdShow);\r
-\r
-static HCONV openConversation (void);\r
-static void closeConversation (HCONV hConv);\r
-static int doFile (HCONV hConv, LPSTR lpszFileName1, LPSTR lpszFileName2);\r
-static int parseCommandLine (HCONV hConv, LPSTR lpszCommandLine);\r
-\r
-/* -- Function Definitions -------------------------------------------------- */\r
-\r
-/*\r
- * Name : ddeCallback\r
- * Function: Gets called by DDEML.\r
- *\r
- */\r
-\r
-HDDEDATA CALLBACK\r
-ddeCallback (UINT uType, UINT uFmt, HCONV hconv,\r
- HSZ hsz1, HSZ hsz2, HDDEDATA hdata,\r
- DWORD dwData1, DWORD dwData2)\r
-{\r
- return (HDDEDATA) NULL;\r
-}\r
-\r
-/*\r
- * Name : WinMain\r
- * Function: The program's entry point function.\r
- *\r
- */\r
-\r
-int WINAPI\r
-WinMain (HINSTANCE hInst,\r
- HINSTANCE hPrev,\r
- LPSTR lpCmdLine,\r
- int nCmdShow)\r
-{\r
- HCONV hConv;\r
- int ret = 0;\r
- UINT uiRet;\r
- \r
- /* Initialise the DDEML library */\r
- uiRet = DdeInitialize (&idInst,\r
- (PFNCALLBACK) ddeCallback,\r
- APPCMD_CLIENTONLY\r
- |CBF_FAIL_ALLSVRXACTIONS,\r
- 0);\r
-\r
- if (uiRet != DMLERR_NO_ERROR)\r
- {\r
- MessageBox (NULL, "Could not initialise DDE management library.",\r
- "winclient", MB_ICONEXCLAMATION | MB_OK);\r
-\r
- return 1;\r
- }\r
-\r
- /* Open a conversation */\r
- hConv = openConversation ();\r
-\r
- if (hConv)\r
- {\r
- /* OK. Next, we need to parse the command line. */\r
- ret = parseCommandLine (hConv, lpCmdLine);\r
-\r
- /* Close the conversation */\r
- closeConversation (hConv);\r
- }\r
- \r
- DdeUninitialize (idInst);\r
-\r
- return ret;\r
-}\r
-\r
-/*\r
- * Name : openConversation\r
- * Function: Start a conversation.\r
- *\r
- */\r
-\r
-static HCONV\r
-openConversation (void)\r
-{\r
- HSZ hszService = NULL, hszTopic = NULL;\r
- HCONV hConv = NULL;\r
-\r
- /* Get the application (service) name */\r
- hszService = DdeCreateStringHandle (idInst,\r
- SERVICE_NAME,\r
- CP_WINANSI);\r
-\r
- if (!hszService)\r
- {\r
- MessageBox (NULL, "Could not create string handle for service.",\r
- "winclient", MB_ICONEXCLAMATION | MB_OK);\r
-\r
- goto error;\r
- }\r
- \r
- /* Get the topic name */\r
- hszTopic = DdeCreateStringHandle (idInst,\r
- TOPIC_NAME,\r
- CP_WINANSI);\r
-\r
- if (!hszTopic)\r
- {\r
- MessageBox (NULL, "Could not create string handle for topic.",\r
- "winclient", MB_ICONEXCLAMATION | MB_OK);\r
-\r
- goto error;\r
- }\r
-\r
- /* Try to connect */\r
- hConv = DdeConnect (idInst, hszService, hszTopic, NULL);\r
-\r
- if (!hConv)\r
- {\r
- STARTUPINFO sti;\r
- PROCESS_INFORMATION pi;\r
- int n;\r
- \r
- /* Try to start the program */\r
- ZeroMemory (&sti, sizeof (sti));\r
- sti.cb = sizeof (sti);\r
- if (!CreateProcess (NULL, PROGRAM_TO_RUN, NULL, NULL, FALSE, 0,\r
- NULL, NULL, &sti, &pi))\r
- {\r
- MessageBox (NULL, "Could not start process.",\r
- "winclient", MB_ICONEXCLAMATION | MB_OK);\r
-\r
- goto error;\r
- }\r
-\r
- /* Wait for the process to enter an idle state */\r
- WaitForInputIdle (pi.hProcess, MAX_INPUT_IDLE_WAIT);\r
-\r
- /* Close the handles */\r
- CloseHandle (pi.hThread);\r
- CloseHandle (pi.hProcess);\r
- \r
- /* Try to connect */\r
- for (n = 0; n < 5; n++)\r
- {\r
- Sleep (CONNECT_DELAY);\r
- \r
- hConv = DdeConnect (idInst, hszService, hszTopic, NULL);\r
-\r
- if (hConv)\r
- break;\r
- }\r
-\r
- if (!hConv)\r
- {\r
- /* Still couldn't connect. */\r
- MessageBox (NULL, "Could not connect to DDE server.",\r
- "winclient", MB_ICONEXCLAMATION | MB_OK);\r
-\r
- goto error;\r
- }\r
- }\r
-\r
- /* Release the string handles */\r
- DdeFreeStringHandle (idInst, hszService);\r
- DdeFreeStringHandle (idInst, hszTopic);\r
-\r
- return hConv;\r
- \r
- error:\r
- if (hConv)\r
- DdeDisconnect (hConv);\r
- if (hszService)\r
- DdeFreeStringHandle (idInst, hszService);\r
- if (hszTopic)\r
- DdeFreeStringHandle (idInst, hszTopic);\r
-\r
- return NULL;\r
-}\r
-\r
-/*\r
- * Name : closeConversation\r
- * Function: Close a conversation.\r
- *\r
- */\r
-\r
-static void\r
-closeConversation (HCONV hConv)\r
-{\r
- /* Shut down */\r
- DdeDisconnect (hConv);\r
-}\r
-\r
-/*\r
- * Name : doFile\r
- * Function: Process a file.\r
- *\r
- */\r
-\r
-int\r
-doFile (HCONV hConv, LPSTR lpszFileName1, LPSTR lpszFileName2)\r
-{\r
- char *buf = NULL;\r
- unsigned len;\r
- \r
- /* Calculate the buffer length */\r
- len = strlen (lpszFileName1) + strlen (lpszFileName2)\r
- + strlen (COMMAND_FORMAT);\r
- \r
- /* Allocate a buffer */\r
- buf = (char *) xmalloc (len);\r
-\r
- if (!buf)\r
- {\r
- MessageBox (NULL, "Not enough memory.",\r
- "winclient", MB_ICONEXCLAMATION | MB_OK);\r
-\r
- return 1;\r
- }\r
-\r
- /* Build the command */\r
- len = wsprintf (buf, COMMAND_FORMAT, lpszFileName1, lpszFileName2);\r
-\r
- len++;\r
- \r
- /* OK. We're connected. Send the message. */\r
- DdeClientTransaction (buf, len, hConv, NULL,\r
- 0, XTYP_EXECUTE, TRANSACTION_TIMEOUT, NULL);\r
-\r
- free (buf);\r
- \r
- return 0;\r
-}\r
-\r
-/*\r
- * Name : getNextArg\r
- * Function: Retrieve the next command line argument.\r
- *\r
- */\r
-\r
-static char *\r
-getNextArg (const char **ptr, unsigned *len)\r
-{\r
- int in_quotes = 0, quit = 0, all_in_quotes = 0;\r
- const char *p = *ptr, *start;\r
- char *buf = NULL;\r
- unsigned length = 0;\r
-\r
- /* Skip whitespace */\r
- while (*p && isspace (*p))\r
- p++;\r
-\r
- /* If this is the end, return NULL */\r
- if (!*p)\r
- return NULL;\r
- \r
- /* Remember where we are */\r
- start = p;\r
- \r
- /* Find the next whitespace character outside quotes */\r
- if (*p == '"')\r
- all_in_quotes = 1;\r
- \r
- while (*p && !quit)\r
- {\r
- switch (*p)\r
- {\r
- case '"':\r
- in_quotes = 1 - in_quotes;\r
- p++;\r
- break;\r
-\r
- case '\\':\r
- if (!in_quotes)\r
- all_in_quotes = 0;\r
- \r
- p++;\r
-\r
- if (!*p)\r
- break;\r
-\r
- p++;\r
- break;\r
-\r
- default:\r
- if (isspace (*p) && !in_quotes)\r
- quit = 1;\r
- else if (!in_quotes)\r
- all_in_quotes = 0;\r
-\r
- if (!quit)\r
- p++;\r
- }\r
- }\r
-\r
- /* Work out the length */\r
- length = p - start;\r
-\r
- /* Strip quotes if the argument is completely quoted */\r
- if (all_in_quotes)\r
- {\r
- start++;\r
- length -= 2;\r
- }\r
- \r
- /* Copy */\r
- buf = (char *) xmalloc (length + 1);\r
-\r
- if (!buf)\r
- return NULL;\r
- \r
- strncpy (buf, start, length);\r
- buf[length] = '\0';\r
-\r
- /* Return the pointer and length */\r
- *ptr = p;\r
- *len = length;\r
-\r
- return buf;\r
-}\r
-\r
-/*\r
- * Name : parseCommandLine\r
- * Function: Process the command line. This program accepts a list of strings\r
- * : (which may contain wildcards) representing filenames.\r
- *\r
- */\r
-\r
-int\r
-parseCommandLine (HCONV hConv, LPSTR lpszCommandLine)\r
-{\r
- char *fullpath, *filepart;\r
- char *arg;\r
- unsigned len, pathlen;\r
- int ret = 0;\r
- HANDLE hFindFile = NULL;\r
- WIN32_FIND_DATA wfd;\r
-\r
- /* Retrieve arguments */\r
- while ((arg = getNextArg ((const char**)&lpszCommandLine, &len)) != NULL)\r
- {\r
- /* First find the canonical path name */\r
- fullpath = filepart = NULL;\r
- pathlen = GetFullPathName (arg, 0, fullpath, &filepart);\r
-\r
- fullpath = (char *) xmalloc (pathlen);\r
-\r
- if (!fullpath)\r
- {\r
- MessageBox (NULL, "Not enough memory.", "winclient",\r
- MB_ICONEXCLAMATION | MB_OK);\r
- \r
- ret = 1;\r
- free (arg);\r
- \r
- break;\r
- }\r
-\r
- GetFullPathName (arg, pathlen, fullpath, &filepart);\r
-\r
- /* Find the first matching file */\r
- hFindFile = FindFirstFile (arg, &wfd);\r
-\r
- if (hFindFile == INVALID_HANDLE_VALUE)\r
- ret = doFile (hConv, fullpath, "");\r
- else\r
- {\r
- /* Chop off the file part from the full path name */\r
- if (filepart)\r
- *filepart = '\0';\r
-\r
- /* For each matching file */\r
- do\r
- {\r
- /* Process it */\r
- ret = doFile (hConv, fullpath, wfd.cFileName);\r
-\r
- if (ret)\r
- break;\r
- }\r
- while (FindNextFile (hFindFile, &wfd));\r
-\r
- FindClose (hFindFile);\r
- }\r
-\r
- /* Release the path name buffers */\r
- free (fullpath);\r
- free (arg);\r
-\r
- if (ret)\r
- break;\r
- }\r
-\r
- return ret;\r
-}\r
-\r
-static void\r
-fatal (const char *s1, const char *s2)\r
-{\r
- error (s1, s2);\r
- exit (1);\r
-}\r
-\r
-/* Print error message. `s1' is printf control string, `s2' is arg for it. */\r
-static void\r
-error (const char* s1, const char* s2)\r
-{\r
- fprintf (stderr, "winclient: ");\r
- fprintf (stderr, s1, s2);\r
- fprintf (stderr, "\n");\r
-}\r
-\r
-/* Like malloc but get fatal error if memory is exhausted. */\r
-\r
-static void *\r
-xmalloc (size_t size)\r
-{\r
- void *result = malloc (size);\r
- if (result == NULL)\r
- fatal ("virtual memory exhausted", (char *) 0);\r
- return result;\r
-}\r
+/* 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. */
+
+/* -- Pre-Include Defines --------------------------------------------------- */
+
+#define STRICT
+
+/* -- Includes -------------------------------------------------------------- */
+
+#include <windows.h>
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+#include <stdlib.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <errno.h>
+
+static void error (const char* s1, const char* s2);
+static void fatal (const char *s1, const char *s2);
+static void * xmalloc (size_t size);
+static char * getNextArg (const char **ptr, unsigned *len);
+
+/* -- Post-Include Defines -------------------------------------------------- */
+
+/* Timeouts & delays */
+#define CONNECT_DELAY 500 /* ms */
+#define TRANSACTION_TIMEOUT 5000 /* ms */
+#define MAX_INPUT_IDLE_WAIT INFINITE /* ms */
+
+/* DDE Strings */
+#define SERVICE_NAME "XEmacs"
+#define TOPIC_NAME "System"
+#define COMMAND_FORMAT "[open(\"%s%s\")]"
+
+/* XEmacs program name */
+#define PROGRAM_TO_RUN "xemacs.exe"
+
+/* -- Constants ------------------------------------------------------------- */
+
+/* -- Global Variables ------------------------------------------------------ */
+
+HINSTANCE hInstance;
+DWORD idInst = 0;
+
+/* -- Function Declarations ------------------------------------------------- */
+
+HDDEDATA CALLBACK ddeCallback (UINT uType, UINT uFmt, HCONV hconv,
+ HSZ hsz1, HSZ hsz2, HDDEDATA hdata,
+ DWORD dwData1, DWORD dwData2);
+
+int WINAPI WinMain (HINSTANCE hInst,
+ HINSTANCE hPrev,
+ LPSTR lpCmdLine,
+ int nCmdShow);
+
+static HCONV openConversation (void);
+static void closeConversation (HCONV hConv);
+static int doFile (HCONV hConv, LPSTR lpszFileName1, LPSTR lpszFileName2);
+static int parseCommandLine (HCONV hConv, LPSTR lpszCommandLine);
+
+/* -- Function Definitions -------------------------------------------------- */
+
+/*
+ * Name : ddeCallback
+ * Function: Gets called by DDEML.
+ *
+ */
+
+HDDEDATA CALLBACK
+ddeCallback (UINT uType, UINT uFmt, HCONV hconv,
+ HSZ hsz1, HSZ hsz2, HDDEDATA hdata,
+ DWORD dwData1, DWORD dwData2)
+{
+ return (HDDEDATA) NULL;
+}
+
+/*
+ * Name : WinMain
+ * Function: The program's entry point function.
+ *
+ */
+
+int WINAPI
+WinMain (HINSTANCE hInst,
+ HINSTANCE hPrev,
+ LPSTR lpCmdLine,
+ int nCmdShow)
+{
+ HCONV hConv;
+ int ret = 0;
+ UINT uiRet;
+
+ /* Initialise the DDEML library */
+ uiRet = DdeInitialize (&idInst,
+ (PFNCALLBACK) ddeCallback,
+ APPCMD_CLIENTONLY
+ |CBF_FAIL_ALLSVRXACTIONS,
+ 0);
+
+ if (uiRet != DMLERR_NO_ERROR)
+ {
+ MessageBox (NULL, "Could not initialise DDE management library.",
+ "winclient", MB_ICONEXCLAMATION | MB_OK);
+
+ return 1;
+ }
+
+ /* Open a conversation */
+ hConv = openConversation ();
+
+ if (hConv)
+ {
+ /* OK. Next, we need to parse the command line. */
+ ret = parseCommandLine (hConv, lpCmdLine);
+
+ /* Close the conversation */
+ closeConversation (hConv);
+ }
+
+ DdeUninitialize (idInst);
+
+ return ret;
+}
+
+/*
+ * Name : openConversation
+ * Function: Start a conversation.
+ *
+ */
+
+static HCONV
+openConversation (void)
+{
+ HSZ hszService = NULL, hszTopic = NULL;
+ HCONV hConv = NULL;
+
+ /* Get the application (service) name */
+ hszService = DdeCreateStringHandle (idInst,
+ SERVICE_NAME,
+ CP_WINANSI);
+
+ if (!hszService)
+ {
+ MessageBox (NULL, "Could not create string handle for service.",
+ "winclient", MB_ICONEXCLAMATION | MB_OK);
+
+ goto error;
+ }
+
+ /* Get the topic name */
+ hszTopic = DdeCreateStringHandle (idInst,
+ TOPIC_NAME,
+ CP_WINANSI);
+
+ if (!hszTopic)
+ {
+ MessageBox (NULL, "Could not create string handle for topic.",
+ "winclient", MB_ICONEXCLAMATION | MB_OK);
+
+ goto error;
+ }
+
+ /* Try to connect */
+ hConv = DdeConnect (idInst, hszService, hszTopic, NULL);
+
+ if (!hConv)
+ {
+ STARTUPINFO sti;
+ PROCESS_INFORMATION pi;
+ int n;
+
+ /* Try to start the program */
+ ZeroMemory (&sti, sizeof (sti));
+ sti.cb = sizeof (sti);
+ if (!CreateProcess (NULL, PROGRAM_TO_RUN, NULL, NULL, FALSE, 0,
+ NULL, NULL, &sti, &pi))
+ {
+ MessageBox (NULL, "Could not start process.",
+ "winclient", MB_ICONEXCLAMATION | MB_OK);
+
+ goto error;
+ }
+
+ /* 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);
+
+ /* Try to connect */
+ for (n = 0; n < 5; n++)
+ {
+ Sleep (CONNECT_DELAY);
+
+ hConv = DdeConnect (idInst, hszService, hszTopic, NULL);
+
+ if (hConv)
+ break;
+ }
+
+ if (!hConv)
+ {
+ /* Still couldn't connect. */
+ MessageBox (NULL, "Could not connect to DDE server.",
+ "winclient", MB_ICONEXCLAMATION | MB_OK);
+
+ goto error;
+ }
+ }
+
+ /* Release the string handles */
+ DdeFreeStringHandle (idInst, hszService);
+ DdeFreeStringHandle (idInst, hszTopic);
+
+ return hConv;
+
+ error:
+ if (hConv)
+ DdeDisconnect (hConv);
+ if (hszService)
+ DdeFreeStringHandle (idInst, hszService);
+ if (hszTopic)
+ DdeFreeStringHandle (idInst, hszTopic);
+
+ return NULL;
+}
+
+/*
+ * Name : closeConversation
+ * Function: Close a conversation.
+ *
+ */
+
+static void
+closeConversation (HCONV hConv)
+{
+ /* Shut down */
+ DdeDisconnect (hConv);
+}
+
+/*
+ * Name : doFile
+ * Function: Process a file.
+ *
+ */
+
+int
+doFile (HCONV hConv, LPSTR lpszFileName1, LPSTR lpszFileName2)
+{
+ char *buf = NULL;
+ unsigned len;
+
+ /* Calculate the buffer length */
+ len = strlen (lpszFileName1) + strlen (lpszFileName2)
+ + strlen (COMMAND_FORMAT);
+
+ /* Allocate a buffer */
+ buf = (char *) xmalloc (len);
+
+ if (!buf)
+ {
+ MessageBox (NULL, "Not enough memory.",
+ "winclient", MB_ICONEXCLAMATION | MB_OK);
+
+ return 1;
+ }
+
+ /* Build the command */
+ len = wsprintf (buf, COMMAND_FORMAT, lpszFileName1, lpszFileName2);
+
+ len++;
+
+ /* OK. We're connected. Send the message. */
+ DdeClientTransaction (buf, len, hConv, NULL,
+ 0, XTYP_EXECUTE, TRANSACTION_TIMEOUT, NULL);
+
+ free (buf);
+
+ return 0;
+}
+
+/*
+ * Name : getNextArg
+ * Function: Retrieve the next command line argument.
+ *
+ */
+
+static char *
+getNextArg (const char **ptr, unsigned *len)
+{
+ int in_quotes = 0, quit = 0, all_in_quotes = 0;
+ const char *p = *ptr, *start;
+ char *buf = NULL;
+ unsigned length = 0;
+
+ /* Skip whitespace */
+ while (*p && isspace (*p))
+ p++;
+
+ /* If this is the end, return NULL */
+ if (!*p)
+ return NULL;
+
+ /* Remember where we are */
+ start = p;
+
+ /* Find the next whitespace character outside quotes */
+ if (*p == '"')
+ all_in_quotes = 1;
+
+ while (*p && !quit)
+ {
+ switch (*p)
+ {
+ case '"':
+ in_quotes = 1 - in_quotes;
+ p++;
+ break;
+
+ case '\\':
+ if (!in_quotes)
+ all_in_quotes = 0;
+
+ p++;
+
+ if (!*p)
+ break;
+
+ p++;
+ break;
+
+ default:
+ if (isspace (*p) && !in_quotes)
+ quit = 1;
+ else if (!in_quotes)
+ all_in_quotes = 0;
+
+ if (!quit)
+ p++;
+ }
+ }
+
+ /* Work out the length */
+ length = p - start;
+
+ /* Strip quotes if the argument is completely quoted */
+ if (all_in_quotes)
+ {
+ start++;
+ length -= 2;
+ }
+
+ /* Copy */
+ buf = (char *) xmalloc (length + 1);
+
+ if (!buf)
+ return NULL;
+
+ strncpy (buf, start, length);
+ buf[length] = '\0';
+
+ /* Return the pointer and length */
+ *ptr = p;
+ *len = length;
+
+ return buf;
+}
+
+/*
+ * Name : parseCommandLine
+ * Function: Process the command line. This program accepts a list of strings
+ * : (which may contain wildcards) representing filenames.
+ *
+ */
+
+int
+parseCommandLine (HCONV hConv, LPSTR lpszCommandLine)
+{
+ char *fullpath, *filepart;
+ char *arg;
+ unsigned len, pathlen;
+ int ret = 0;
+ HANDLE hFindFile = NULL;
+ WIN32_FIND_DATA wfd;
+
+ /* Retrieve arguments */
+ while ((arg = getNextArg ((const char**)&lpszCommandLine, &len)) != NULL)
+ {
+ /* First find the canonical path name */
+ fullpath = filepart = NULL;
+ pathlen = GetFullPathName (arg, 0, fullpath, &filepart);
+
+ fullpath = (char *) xmalloc (pathlen);
+
+ if (!fullpath)
+ {
+ MessageBox (NULL, "Not enough memory.", "winclient",
+ MB_ICONEXCLAMATION | MB_OK);
+
+ ret = 1;
+ free (arg);
+
+ break;
+ }
+
+ GetFullPathName (arg, pathlen, fullpath, &filepart);
+
+ /* Find the first matching file */
+ hFindFile = FindFirstFile (arg, &wfd);
+
+ if (hFindFile == INVALID_HANDLE_VALUE)
+ ret = doFile (hConv, fullpath, "");
+ else
+ {
+ /* Chop off the file part from the full path name */
+ if (filepart)
+ *filepart = '\0';
+
+ /* For each matching file */
+ do
+ {
+ /* Process it */
+ ret = doFile (hConv, fullpath, wfd.cFileName);
+
+ if (ret)
+ break;
+ }
+ while (FindNextFile (hFindFile, &wfd));
+
+ FindClose (hFindFile);
+ }
+
+ /* Release the path name buffers */
+ free (fullpath);
+ free (arg);
+
+ if (ret)
+ break;
+ }
+
+ return ret;
+}
+
+static void
+fatal (const char *s1, const char *s2)
+{
+ error (s1, s2);
+ exit (1);
+}
+
+/* Print error message. `s1' is printf control string, `s2' is arg for it. */
+static void
+error (const char* s1, const char* s2)
+{
+ fprintf (stderr, "winclient: ");
+ fprintf (stderr, s1, s2);
+ fprintf (stderr, "\n");
+}
+
+/* Like malloc but get fatal error if memory is exhausted. */
+
+static void *
+xmalloc (size_t size)
+{
+ void *result = malloc (size);
+ if (result == NULL)
+ fatal ("virtual memory exhausted", (char *) 0);
+ return result;
+}